\documentclass{ctexart}
\usepackage{ctex}
\usepackage{cite}
\usepackage{float}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage[colorlinks,linkcolor=blue]{hyperref}
\usepackage{geometry}
\usepackage{hyperref}
\usepackage{amsfonts, amssymb}
\usepackage{url}
\usepackage{array}
\usepackage{xcolor}
\usepackage{listings}
\usepackage{fontspec}

\setmonofont{Consolas}
\linespread{1.5}
\pagestyle{plain}
\geometry{a4paper, scale=0.9}

\ctexset{
    section={
		format+ = \zihao{-3} \heiti \raggedright,
		name = {,、},
		number = \chinese{section},
		beforeskip = 1.0ex plus 0.2ex minus .2ex,
		afterskip = 1.0ex plus 0.2ex minus .2ex,
		aftername = \hspace{0pt}
    },
    % subsection={
	% 	format+ = \zihao{4} \kaishu \raggedright,
	% 	number = \chinese{subsection},
	% 	name = {（,）},
	% 	beforeskip = 1.0ex plus 0.2ex minus .2ex,
	% 	afterskip = 1.0ex plus 0.2ex minus .2ex,
	% 	aftername = \hspace{0pt}
	% },
	% subsubsection={
	% 	format+ = \zihao{-4} \fangsong \centering,
	% 	number = \ttfamily\arabic{subsubsection},
	% 	name = {,.},
	% 	beforeskip = 1.0ex plus 0.2ex minus .2ex,
	% 	afterskip = 1.0ex plus 0.2ex minus .2ex,
	% 	aftername = \hspace{0pt}
	% }
}

\lstset{
    basicstyle          =   \sffamily,           % 基本代码风格
    keywordstyle        =   \bfseries,           % 关键字风格
    commentstyle        =   \rmfamily\itshape,   % 注释的风格，斜体
    stringstyle         =   \ttfamily,           % 字符串风格
    flexiblecolumns,                             % 别问为什么，加上这个
    numbers             =   left,                % 行号的位置在左边
    showspaces          =   false,               % 是否显示空格，显示了有点乱，所以不现实了
    numberstyle         =   \zihao{-5}\ttfamily, % 行号的样式，小五号，tt等宽字体
    showstringspaces    =   false,
    captionpos          =   t,                   % 这段代码的名字所呈现的位置，t指的是top上面
    frame               =   lrtb,                % 显示边框
    language            =   [ANSI]{C},
    breaklines          =   true,
}

\definecolor{mygreen}{rgb}{0,0.6,0}
\definecolor{mygray}{rgb}{0.5,0.5,0.5}
\definecolor{mymauve}{rgb}{0.58,0,0.82}
\lstset{ %
        backgroundcolor=\color{white},   % choose the background color
        basicstyle=\footnotesize\ttfamily,        % size of fonts used for the code
        columns=fullflexible,
        breaklines=true,                 % automatic line breaking only at whitespace
        captionpos=b,                    % sets the caption-position to bottom
        tabsize=4,
        commentstyle=\color{mygreen},    % comment style
        escapeinside={\%*}{*)},          % if you want to add LaTeX within your code
        keywordstyle=\color{blue},       % keyword style
        stringstyle=\color{mymauve}\ttfamily,     % string literal style
        frame=single,
        rulesepcolor=\color{red!20!green!20!blue!20},
        % identifierstyle=\color{red},
        backgroundcolor=\color[RGB]{245,245,244},
        numberstyle=\color[RGB]{0,192,192},
        stringstyle=\rmfamily\slshape\color[RGB]{128,0,0},
        identifierstyle=\bf,
        language=C++,
}

\title{\huge \textbf{《八股文纪实，for实习、秋招》\\ 史煜鑫}}
\date{}

\begin{document}

    \begin{figure}
        \centering
        \vspace*{8\baselineskip}
        \includegraphics[scale=0.4]{Figures/封面2.png}
        \vspace*{4\baselineskip}
    \end{figure}
    
    \maketitle

    \begin{table}[htb]
        \LARGE
        \renewcommand\arraystretch{1.5}
        \begin{center}
            \begin{tabular}{ccc}
                最后编译日期： & \today \\ \cline{2-2}
            \end{tabular}
        \end{center}
    \end{table}

    \begin{center}
        本文档使用 \LaTeX{} 编写
    \end{center}

    \clearpage

    本文档，涵盖了，本人在准备2024届实习和秋招的过程中，对八股文模块进行的准备工作。

    原本打算，基于CSAPP\cite{csapp}进行这一部分学习，但是理想很丰满，现实很骨感，这部分工作现在主要基于整理了相关内容的网站。

    \tableofcontents

    \clearpage
    \section{面试·计算机基础}

    \href{https://www.iamshuaidi.com/c-interview-2/c-interview}{C++}

    \href{https://www.iamshuaidi.com/14343.html}{Linux}

    \href{https://www.iamshuaidi.com/1402.html}{MySQL}

    \href{https://www.iamshuaidi.com/1346.html}{操作系统}

    \href{https://www.iamshuaidi.com/673.html}{计算机网络常见问题}

    \href{https://www.iamshuaidi.com/359.html}{计算机网络入门指南}

    \href{https://xiaolincoding.com/}{小林coding}

    （Java \& 计算机基础）C:/Users/24966/OneDrive/两位/2024秋招/v3.0-JavaGuide面试突击版.pdf

    C:/Users/24966/OneDrive/两位/2024秋招/代码随想录知识星球精华-大厂面试八股文第二版.pdf

    \subsection{计算机网络}

    \subsubsection{计算机网络五层结构入门}

    \href{https://www.iamshuaidi.com/747.html}{计算机网络五层结构入门}

    计算机网络的五层模型：物理层（Physical Layer）、数据链路层（Datalink Layer）、网络层（Network Layer）、传输层（Transport Layer）、应用层（Application Layer）。

    物理层负责在物理上连接两台计算机（光纤、双绞线，等）。

    以太网协议规定，一组01电信号构成一个数据包，称之为帧，每一个数据帧由标头Head和数据Data两部分组成。帧的大小一般为64到1518个字节。假如需要传送的数据很大的话，就分成多个桢来进行传送。

    标头部分固定为18个字节，包含发送者、接收者等信息。

    每一张网卡，都会有一个唯一的地址标识，叫做MAC地址，MAC地址由48个二进制位组成，MAC地址作用于数据链路层。

    在同一个子网中，一台计算机向另一台计算机发送数据，会通过广播的方式实现，发送的数据包中包含目标计算机的MAC地址，另一台计算机收到这个数据包后，会对比数据包中的MAC地址和自身的MAC地址，如果相同就收下这个数据包，如果不同就丢弃这个数据包。

    一台计算机通过ARP协议获知子网中其他计算机的MAC地址。

    一台计算机发送数据给另一台计算机，如果另一台计算机也在同一个子网里，就用广播的形式发送数据，如果另一台计算机不在同一个子网中，就把数据交给网关，网关进行转发。

    IP地址分为网络部分和主机部分，由子网掩码确定，子网掩码为1的部分为网络部分，为0的部分为主机部分。

    ARP协议通过广播的形式给同一个子网中的每台电脑发送一个数据包（这个数据包会包含接收方的IP地址）。对方收到这个数据包之后，会取出IP地址与自身的对比，如果相同，则把自己的MAC地址回复给对方，否则就丢弃这个数据包。这样，计算机就能知道其他计算机的MAC地址了。（此时发送的数据包中，MAC地址部分填的是一个特殊值）

    DNS服务器，DNS工作在应用层。

    端口（Port）工作在传输层，端口用来让特定的应用程序接收网络层传输来的数据。

    网络层建立主机到主机的通信，而传输层建立端口到端口的通信。

    传输层的两大协议是TCP和UDP。

    应用层负责指定各种各样的规则解析传输层传输来的数据。

    应用层，对应的数据形式是，报文（Message）；

    传输层，对应的数据形式是，数据段、报文段（Segment）；

    网络层，对应的数据形式是，分组、数据包、包（Packet）；

    数据链路层，对应的数据形式是，帧（Frame）；

    物理层，对应的数据形式是，比特流；

    \subsubsection{通信双方如何保证信息不丢失}

    \href{https://www.iamshuaidi.com/749.html}{通信双方如何保证信息不丢失}

    网络层中，数据以分组，也叫包（Packet）的形式进行传输，分组有可能在传输过程中受信道干扰出现差错，比如0变1，1变0，或者，在传输过程中，分组丢失，丢包了。

    首先，分组中有序号，标明分组的顺序，然后，分组中有校验码，用于校验分组是否出错，如果分组没有出错，则接收方回复ACK分组，如果分组出错了，则接收方回复NAK，如果发送方接收到了NAK分组或者无法分辨接收到的回复是ACK还是NAK，就重传之前的分组。

    ACK，Acknowledge Character，Acknowledgment，接收方收到消息后告知发送方的消息。

    NAK/NACK，Negative Acknowledgment，接收方没有收到消息后告知发送方的消息。

    REX，Retransmission，发送方得知数据丢失之后，重传数据。

    滑动窗口协议（GBN协议，后退N帧协议），发送方会维持一个滑动窗口，位于窗口内的所有数据包都可以发送，中途无需等待ACK消息，接收方则采用累积确认模式，只需要对最后一个到达的包发送ACK，表示这个包及以前的都收到了。如果发生超时，就会重传所有未被确认的包（计时器针对窗口内所有的包设置，并不是一个包一个计时器）。

    滑动窗口协议的缺点是，如果第n个包收到了，第n-1个包没有收到，则n也要重传，比较浪费，所以，就有了选择重传（SR）的改进，在选择重传中，接收方收到失序的分组时，会把它缓存起来，直到拼凑到分组按序，才把分组传输给上一层。而发送方会为每个分组设置一个定时器，这样，只需要重传那些没有被接收方正确接收的分组就可以了。

    \href{https://zhuanlan.zhihu.com/p/104322256}{【知乎】谈谈网络通信中的 ACK、NACK 和 REX}

    \subsubsection{集线器、交换机与路由器有什么区别？}

    \href{https://www.iamshuaidi.com/1776.html}{集线器、交换机与路由器有什么区别？}

    集线器（HUB）通过网线直接传输数据，工作在物理层，只能进行广播，各设备处于同一冲突域内。

    交换机（Switch）工作在数据链路层，能够识别每一个网口上连接的设备（会有一个MAC地址和端口的映射表），可以实现任意两台电脑的互联。

    路由器（Router）通过IP进行寻址，工作在网络层，使用IP地址指引数据从一个网络到另一个网络的额传输，可以承担网关的角色。

    \subsubsection{TCP拥塞控制}

    \href{https://www.iamshuaidi.com/1913.html}{TCP拥塞控制}

    拥塞控制与网络的拥堵情况相关联，流量控制与接收方的缓存状态相关联，

    假设A是发送方，B是接收方，A与B在三次握手之后，建立了连接，此时A还不知道网络的拥塞状况，还不知道一次性发送多少个包合适，我们将A一次性发送的数据包的数量称之为拥塞窗口，记为N。

    N一开始会指数增长，到达阈值\textbf{ssthresh}后，线性增长；指数增长的阶段我们称之为\textbf{慢启动}，线性增长的阶段我们称之为\textbf{拥塞避免}。

    N不断增长，最后一定会出现超时，记出现超时时候的N为MAX，这时候，开始新一轮的慢启动和拥塞避免，不过，此时令ssthresh=MAX/2。

    如果在拥塞控制的过程中，出现了丢包或者包损坏的情况，我们将通过冗余ACK来处理：

    \begin{figure}[H]
        \centering
        \includegraphics[scale=0.5]{Figures/冗余ACK，1.png} 
        \caption{冗余ACK}
    \end{figure}

    如上如所示，M1和M2都顺利抵达了，M3丢失，则B收到M4后，会知晓M3没有发送成功，则此时重复发送M2的ACK，重复三次以后，A就知道了M3丢了，这时候A就不用等待M3的计时器到期，可以直接快速重传M3，并在快速重传的同时，令ssthresh=MAX/2，并令N=ssthresh，继续进行拥塞控制的过程。

    上面这种情况，也成为快速恢复，具有快速恢复功能的TCP被称为TCP Reno。

    还有一种TCP，无论是超时还是连续收到3次相同的ACK，都会把N重新设为1，这个版本称为TCP Tahoe。

    关键字：慢启动（慢开始）、拥塞避免（拥塞控制）、快速重传、快速恢复。

    拥塞窗口，cwnd，congestion window；
    
    发送窗口，swnd，sender window；

    接收窗口，rwnd，receiver window；

    发送方可以按照接收方允许的接收窗口大小，一次性发送最多rwnd个包。rwnd的大小是接收方根据自身的情况动态改变的，每次接收方返回ACK的时候，都会随着ACK返回rwnd的大小。

    cwnd会随着慢启动和拥塞避免，逐渐向着rwnd靠近。cwnd取决于网络的状态。在实际中，rwnd一般会比cwnd大。

    \subsubsection{TCP流量控制}

    \href{https://www.iamshuaidi.com/1915.html}{TCP流量控制}

    接收方每次收到数据包，在发送ACK报文的时候，可以同时告知发送方自己剩下多少缓存空间，剩余缓存区的大小，我们称之为\textbf{接收窗口，rwnd，receiver window}，发送发接收到接收方发送的rwnd后，就会调整自己的发送窗口大小，即swnd。

    如果swnd调整为0，就会停止发送，同时开启一个定时器，每隔一段时间发送一个\textbf{测试报文}，如果接收方还不能接收数据，就刷新计时器，如果接收方可以接收数据了，就会返回rwnd的大小，重新开始发送数据。

    一般情况下，$ rwnd \ge swnd $ 。

    \subsubsection{TCP的三次握手}

    \href{https://www.iamshuaidi.com/1918.html}{TCP的三次握手}

    SYN报文，Synchronize Sequence Numbers。

    \begin{itemize}
        \item 第一次握手，客户端向服务器发送SYN报文。
        \item 第二次握手，服务器收到客户端发送的SYN报文之后，应答客户端一个SYN+ACK报文。
        \item 第三次握手，客户端收到SYN+ACK报文之后，应答服务器一个ACK报文。
        \item 服务器收到ACK报文之后，三次握手完成，连接建立。
    \end{itemize}

    如果第一次握手成功，说明客户端的发送能力，和，服务器的接收能力，都是正常的；但是双方都不知道对方的情况；

    如果第二次握手成功，说明客户端的接收能力，和，服务器的发送能力，都是正常的；而且，客户端可以确认服务器的接收和发送能力正常，但服务器并不确认客户端的接受能力正常。

    如果第三次握手成功，服务器也能正式确认，客户端的发送能力和接收能力都正常，连接顺利建立。

    \textbf{TCP的11个状态包括，}Listen、SYN-Sent、SYN-Received、Established、FIN-Wait-1、FIN-Wait-2、Close-Wait、Closing、Last-ACK、Time-Wait、Closed。

    \begin{figure}[H]
        \centering
        \includegraphics[scale=0.6]{Figures/TCP，三次握手.png}
        \caption{TCP三次握手状态转移详解}
    \end{figure}

    \begin{itemize}
        \item 第一次握手，客户端初始状态为Closed，然后客户端发送一个SYN报文，并处于SYN-Sent状态，SYN报文指明客户端的初始化序列号，ISN，Initial Sequence Number，记客户端的初始化序列号为ISNc。
        \item 第二次握手，服务器一开始处于Closed状态，创建Socket后状态变为Listen，服务器收到来自客户端的SYN报文之后，会回复一个SYN报文，指明自己的ISN，记服务器的初始化序列号为ISNs，同时，服务器还会返回一个ACK报文，报文的内容为ISNc+1，此时，服务器的状态为SYN-Received。
        \item 第三次握手，客户端收到服务器的SYN和ACK之后，返回一个ACK报文，报文的内容为ISNs+1，然后，客户进入Established状态。
        \item 最后，服务器收到来自客户端的ACK报文，也进入Established状态，连接正式建立。
    \end{itemize}

    初始化序列号为动态生成，服务器第一次收到客户端的SYN之后，就会处于SYN-Received状态，此时双方还没有完全建立起连接，服务器会把此种状态下请求连接放在一个队列里，我们把这种队列称之为\textbf{半连接队列}。当然还有一个\textbf{全连接队列}，就是已经完成三次握手，建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。

    第二次握手过程中，服务器发送完SYN-ACK报文，如果过了一段时间没有收到客户端返回的ACK报文，会进行重传，如果重传次数超过系统限制，这个连接就会从半连接队列中删除。

    第一次、第二次握手中，不能携带数据，第三次握手时，客户端已经正式建立连接，所以第三次握手可以携带数据。

    \subsubsection{TCP的四次挥手}

    \href{https://www.iamshuaidi.com/1921.html}{TCP的四次挥手}

    \begin{figure}[H]
        \centering
        \includegraphics[scale=0.6]{Figures/TCP，四次挥手.png}
        \caption{TCP四次挥手状态转移详解}
    \end{figure}

    最初，客户端和服务器都处于Established的状态，这里假设客户端要断开连接。

    \begin{itemize}
        \item 第一次挥手，客户端向服务端发送一个FIN报文，报文中指定一个序列号，然后客户端处于FIN-Wait-1状态。
        \item 第二次挥手，服务器收到FIN报文后，会回复一个ACK报文，报文的序列号是客户端序列号+1，表明服务器收到了客户端的报文，然后，服务器处于Close-Wait状态，客户端在收到对于第一个FIN报文的ACK后，进入Fin-Wait-2状态。
        \item 第三次挥手，如果服务器也准备断开连接，则会向客户端发送一个FIN报文，报文中指定一个序列号，然后，服务器处于Last-ACK状态。
        \item 第四次挥手，客户端收到来自服务器的FIN报文后，回复一个ACK报文，报文的序列号为服务器序列号+1，然后，客户端进入Time-Wait状态，过一段时间后，客户端进入Closed状态。
        \item 服务器收到ACK报文后，进入Closed状态。
    \end{itemize}

    FIN应该是Finish的缩写。

    Time-Wait状态的意义是，如果服务器没有收到第四次挥手的ACK报文，会重新发送FIN报文，然后，客户端就可以知道之前的ACK报文没有收到，并重新发送。

    \begin{itemize}
        \item Listen，侦听来自远方TCP端口的连接请求
        \item SYN-Sent，侦听来自远方TCP端口的连接请求
        \item SYN-Received，在收到和发送一个连接请求后等待对连接请求的确认
        \item Established，代表一个打开的连接，数据可以传送给用户
        \item FIN-Wait-1，等待远程TCP的连接中断请求，或先前的连接中断请求的确认
        \item FIN-Wait-2，从远程TCP等待连接中断请求
        \item Close-Wait，等待从本地用户发来的连接中断请求
        \item Closing，等待远程TCP对连接中断的确认
        \item Last-ACK，等待远程TCP对连接中断的确认
        \item Time-Wait，等待足够的时间以确保远程TCP接收到连接中断请求的确认
        \item Closed，没有任何连接状态
    \end{itemize}

    如果是在，高并发，短连接的业务场景中，会有大量的TCP连接处于Time-Wait的状态，也就是有大量的socket被占用，解决方法有：

    net.ipv4.tcp\_tw\_reuse = 1，表示可以将处于Time-Wait状态的socket用于新的TCP连接。

    net.ipv4.tcp\_tw\_recycle = 1，表示处于Time-Wait状态的socket可以快速回收。

    \subsubsection{HTTP协议}

    \href{https://www.iamshuaidi.com/1924.html}{HTTP协议}

    Hyper Text Transfer Protocol，HTTP是基于TCP-IP的应用层协议，规定了客户端和服务端之间的通信格式，默认使用80端口。

    HTTP0.9，只有get命令，只能返回HTML格式的数据。

    HTTP1.0，有了get、post、head命令，可以传输多种格式。

    HTTP请求的第一行，会包括方法、文档路径、HTTP协议版本，接下来的每一行都表示一个标头header，然后以一个空行结尾，接下来还可以包含一些其他数据，主要为post方法使用。

    HTTP响应的第一行，包括了使用的HTTP版本协议和状态码，接下来的每一行都是一个标头header，然后以一个空行结尾，然后是数据部分。

    \href{https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Session}{【MDN】典型的HTTP会话}

    header中，Contet-Type，表示服务器返回数据的MIME-Type类型，Accept表示客户端接收的类型。

    Content-Encoding和Accept-Encoding表示数据压缩的方式，和能接受的压缩方式。

    HTTP1.0中，同一个TCP连接不能复用，实践中会添加非标准的header，Connection：keep-alive来要求保持TCP连接。

    HTTP1.1中，TCP连接默认不关闭，可以被多个HTTP请求复用。同时，\textbf{加入了管道机制，pipelining}，即，同一个TCP连接里，可以同时发送多个HTTP请求，然后服务器一起回复，这时候，就需要引入一个Content-Length的header，表明消息的长度，这个长度之后的数据属于另一个HTTP Response。

    如果要使用Content-Length，前提是服务器要把数据都准备好然后要一起发送，如果遇到耗时的操作就会耽误时间，这时候的处理方案是\textbf{分块传输编码}，\href{https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Transfer-Encoding}{【MDN】Transfer-Encoding}，数据将分块传输，每一块数据前会有一个数字指明接下来的数据块的大小，大小为0表示传输结束。

    HTTP1.1还添加了host标头，这样，就可以让一个IP配置上多个域名。

    HTTP2中，所有数据，包括标头和数据主体，都是二进制的（HTTP1.1的标头部分是ASCII的，数据部分可以是二进制也可以是文本），统称为帧frame，头信息帧，数据帧。

    HTTP2会\textbf{多工（Multiplexing）}复用TCP连接，举例来说，在一个TCP连接里面，服务器同时收到了A请求和B请求，于是先回应A请求，结果发现处理过程非常耗时，于是就发送A请求已经处理好的部分， 接着回应B请求，完成后，再发送A请求剩下的部分。

    因为 HTTP/2 的数据包是不按顺序发送的，同一个连接里面连续的数据包，可能属于不同的回应。因此，必须要对数据包做标记，指出它属于哪个回应。

    HTTP/2 将每个请求或回应的所有数据包，称为一个\textbf{数据流（stream）}。每个数据流都有一个独一无二的编号。数据包发送的时候，都必须标记数据流ID，用来区分它属于哪个数据流。另外还规定，客户端发出的数据流，ID一律为奇数，服务器发出的，ID为偶数。

    数据流发送到一半的时候，客户端和服务器都可以发送信号（RST-STREAM帧），取消这个数据流。1.1版取消数据流的唯一方法，就是关闭TCP连接。这就是说，HTTP/2 可以取消某一次请求，同时保证TCP连接还打开着，可以被其他请求使用。

    客户端还可以指定数据流的优先级。优先级越高，服务器就会越早回应。

    HTTP 协议不带有状态，每次请求都必须附上所有信息。所以，请求的很多字段都是重复的，比如Cookie和User Agent，一模一样的内容，每次请求都必须附带，这会浪费很多带宽，也影响速度。

    HTTP/2 对这一点做了优化，引入了\textbf{头信息压缩机制（header compression）}。一方面，头信息使用gzip或compress压缩后再发送；另一方面，客户端和服务器同时维护一张头信息表，所有字段都会存入这个表，生成一个索引号，以后就不发送同样字段了，只发送索引号，这样就提高速度了。

    HTTP/2 允许服务器未经请求，主动向客户端发送资源，这叫做\textbf{服务器推送（server push）}。

    常见场景是客户端请求一个网页，这个网页里面包含很多静态资源。正常情况下，客户端必须收到网页后，解析HTML源码，发现有静态资源，再发出静态资源请求。其实，服务器可以预期到客户端请求网页后，很可能会再请求静态资源，所以就主动把这些静态资源随着网页一起发给客户端了。

    \subsubsection{HTTPS协议}

    \href{https://www.iamshuaidi.com/1926.html}{HTTPS协议}

    HTTP默认使用80端口，HTTPS默认使用443端口，HTTPS需要向机构购买证书。

    非对称加密，公钥，私钥，用公钥加密的数据，只有对应的私钥才能解密。

    但是如果直接使用非对称加密的话，仍然不能保证安全，因为可能有一个中间人截留双方的公钥，然后给双方发送自己的公钥，这样，双方的信息就在中间人那里透明了。

    上面的问题在于，客户端不知道得到的公钥是不是真的属于所请求的服务器的，数字证书可以解决这个问题。

    首先，需要一个\textbf{认证中心（CA，Certificate Authority）}，

    然后，服务器在传输公钥的过程中，将公钥以及服务器的信息通过哈希算法生成一个信息摘要，

    然后，服务器将信息摘要用CA提供的私钥来加密形成\textbf{数字签名（digital signature）}，

    最后，服务器信息、公钥、数字签名，一起形成了服务器的数字证书，

    客户端得到数字证书之后，就可以用CA提供的公钥对数字证书中的数字签名进行解密，然后和数字证书中的其余部分进行对比。

    \textbf{哈希算法（服务器公钥 + 服务器信息） = 信息摘要}

    \textbf{CA私钥（信息摘要） = 数字签名}

    \textbf{服务器公钥 + 服务器信息 + 数字签名 = 数字证书}

    \textbf{CA公钥（数字签名） = 信息摘要 = 哈希算法（服务器公钥 + 服务器信息）}

    这样，客户端就可以比对数字签名中的信息和数字证书中的其他信息。

    \subsubsection{SSL/TLS协议}

    \href{https://www.iamshuaidi.com/1959.html}{SSL/TLS协议}

    HTTPS本质上是HTTP加上一层SSL加密，SSL/TLS目的是解决明文通信的\textbf{窃听、篡改、冒充}三大风险，SSL/TLS希望达到，所有信息加密传播无法窃听、具有校验机制无法篡改、配备身份证书防止冒充。

    SSL/TLS的基本思路是，客户端向服务端索取公钥，用公钥加密信息，然后服务器用私钥解密。

    将公钥放在数字证书中，防止公钥被篡改。

    由于非对称加密运算速度慢，所以，每一次会话（session），服务器和客户端都生成一个session key，用公钥私钥加密session key，然后用session key加密要传输的数据，这样数据就是对称加密的所以速度快，非对称加密只需要用来处理session key。

    所以，SSL/TLS的工作流程为：

    \begin{itemize}
        \item 客户端索要服务器的公钥并进行验证。
        \item 客户端和服务器协商形成session key。
        \item 双方使用session key进行加密通信。
    \end{itemize}

    上面的前两部，称为SSL/TLS的握手阶段。

    \begin{figure}[H]
        \centering
        \includegraphics[scale=0.6]{Figures/SSL-TLS的握手.png}
        \caption{SSL/TLS握手过程中的四次通信}    
    \end{figure}

    \subsubsection{DNS，Domain Name System}

    \href{https://www.iamshuaidi.com/1928.html}{DNS，Domain Name System}

    DNS服务器的地址，有可能由网关每次动态分配（DHCP机制），也可以是固定的IP。

    以www.baidu.com为例，其真正的域名应该是，www.baidu.com.root，简写为www.baidu.com.，其中，.root为\textbf{根域名，Root Domain}，.com为\textbf{顶级域名，Top-Level Domain，TLD}，.baidu为\textbf{次级域名，Second-Level Domain，SLD}，www为\textbf{主机名，Host}。

    DNS根据域名的层级，进行分级查询，每一级域名，都有自己的NS（Name Server）记录，NS记录指向该级域名的域名服务器。

    分级查询，就是从根域名开始，查询每一级域名的NS记录，知道查询到最终的IP地址。

    \subsubsection{DHCP，动态主机配置协议，Dynamic Host Configuration Protocol}

    \href{https://www.iamshuaidi.com/1932.html}{DHCP，动态主机配置协议，Dynamic Host Configuration Protocol}

    当一台新的电脑接入网络时，会先广播一个\textbf{discover报文（UDP）}，广播到局域网内所有主机，目标的IP和端口设置为255.255.255.255:68，自己的IP和端口设置为0.0.0.0:67。

    当DHCP服务器接收到这个报文以后（发现源地址是0.0.0.0，就知道有新接入的主机要请求IP），会返回一个\textbf{offer报文}，报文中包含IP地址、子网掩码、网关地址、IP有效期等信息。

    offer报文也以广播的形式发送，offer报文的目标IP和端口号为255.255.255.255:68，源IP使用DHCP服务器自己的IP，源端口号为67，由于discover报文中包含了新接入主机的MAC地址，发送offer报文时只需要将数据链路层上的MAC地址填为目标计算机的MAC地址，就能让目标计算机收到offer报文。

    新接入的计算机收到offer报文，并确定使用这个IP后，会发送一个\textbf{request报文}到提供这个IP的DHCP服务器。

    DHCP服务器收到request报文后，会回复一个ACK报文，目标计算机收到ACK报文后，标志着获得的IP可以正式使用了。

    如果当前局域网中没有DHCP服务器，discover报文就会通过网关进行转发。

    当IP的租期到达1/2时，计算机会向DHCP服务器发送单播request报文，试图进行IP租期的更新，如果DHCP服务器同意续租，会回复ACK报文，如果不同意，会回复NAK报文。

    如果续约失败，当租期到达7/8时，计算机会广播request报文，DHCP服务器的处理方式和处理首次分配一样。

    DHCP报文，包括，DHCP Discover，DHCP Offer，DHCP Request，DHCP ACK，DHCP NAK，DHCP Release，DHCP Decline，DHCP Inform。

    DHCP Release，当计算机不需要再使用分配到的IP地址时，会向DHCP服务器发送Release报文，DHCP服务器就会释放被分配的服务器。

    DHCP Inform，如果计算机需要有关被分配的IP的更加详细的配置信息，则发送Inform报文到DHCP服务器请求数据，DHCP服务器使用ACK报文进行回应。

    \subsubsection{广播路由算法}

    \href{https://www.iamshuaidi.com/1934.html}{广播路由算法}

    广播风暴、控制广播风暴、生成树广播；

    N次单播，无控制的洪泛、受控的洪泛、生成树广播；

    \subsubsection{SQL注入攻击}

    \href{https://www.iamshuaidi.com/1961.html}{SQL注入攻击}

    SQL预编译，参数绑定；正则表达式过滤输入参数；

    \subsubsection{XSS攻击}

    \href{https://www.iamshuaidi.com/1966.html}{XSS攻击}

    XSS是指恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点，进而添加一些脚本代码嵌入到web页面中去，使别的用户访问都会执行相应的嵌入代码，从而盗取用户资料、利用用户身份进行某种动作或者对访问者进行病毒侵害的一种攻击方式。
    
    漏洞产生的根本原因是 太相信用户提交的数据，对用户所提交的数据过滤不足所导致的，因此解决方案也应该从这个方面入手，具体方案包括：

    将重要的cookie标记为http only, 这样的话Javascript 中的document.cookie语句就不能获取到cookie了（如果在cookie中设置了HttpOnly属性，那么通过js脚本将无法读取到cookie信息，这样能有效的防止XSS攻击）；

    表单数据规定值的类型，例如：年龄应为只能为int、name只能为字母数字组合。。。。

    对数据进行Html Encode 处理

    过滤或移除特殊的Html标签，例如: < script >, < iframe > , < for <, > for>, \&quot for

    过滤JavaScript 事件的标签，例如 “onclick=”, “onfocus” 等等。

    \subsubsection{OSI七层模型和各自的功能}

    \href{https://www.iamshuaidi.com/3612.html}{OSI七层模型和各自的功能}

    \begin{enumerate}
        \item 物理层，Physical：底层数据传输，如网线；网卡标准；传输的数据为\textbf{比特流Bits}。
        \item 数据链路层，Data Link：定义数据的基本格式，如何传输，如何标识；如网卡MAC地址；传输的数据为\textbf{帧frame}。
        \item 网络层，Network：定义IP编址，定义路由功能；如不同设备的数据转发；传输的数据被称为\textbf{包package}。
        \item 传输层，Transport：端到端传输数据的基本功能；如 TCP、UDP；传输的数据被称为\textbf{段segment}。
        \item 会话层，Session：控制应用程序之间会话能力；如不同软件数据分发给不同软件，SSL，TSL，等。
        \item 表示层，Presentation：数据格式标识，基本压缩加密功能。
        \item 应用层，Application：各种应用软件，包括 Web 应用，HTTP，FTP，SMTP等。
    \end{enumerate}

    四层模型如下：

    \begin{enumerate}
        \item 数据链路层
        \item 网络层，IP
        \item 传输层，TCP、UDP
        \item 应用层
    \end{enumerate}

    五层模型如下：

    \begin{enumerate}
        \item 物理层
        \item 数据链路层
        \item 网络层
        \item 传输层
        \item 应用层
    \end{enumerate}

    \begin{itemize}
        \item 网络七层模型是一个标准，而非实现。
        \item 网络四层模型是一个实现的应用模型。
        \item 网络的四层模型由七层模型简化合并而来。
        \item 七层来自OSI，四层基于TCP/IP。
        \item 5层只是OSI（Open System Interconnect）和TCP/IP的综合，是业界产生出来的非官方协议模型，但是很多具体的应用。实际应用还是TCP/IP的四层结构。
    \end{itemize}

    \subsubsection{TCP、UDP，区别，应用场景}

    \href{https://www.iamshuaidi.com/679.html}{TCP、UDP，区别，应用场景}

    \textbf{TCP（Transmission Control Protocol）协议的主要特点：}

    \begin{itemize}
        \item TCP是面向连接的运输层协议；所谓面向连接就是双方传输数据之前，必须先建立一条通道，例如三次握手就是建议通道的一个过程，而四次挥手则是结束销毁通道的一个其中过程。
        \item 每一条TCP连接只能有两个端点（即两个套接字），只能是点对点的；
        \item TCP提供可靠的传输服务。传送的数据无差错、不丢失、不重复、按序到达；
        \item TCP提供全双工通信。允许通信双方的应用进程在任何时候都可以发送数据，因为两端都设有发送缓存和接受缓存；
        \item 面向字节流。虽然应用程序与TCP交互是一次一个大小不等的数据块，但TCP把这些数据看成一连串无结构的字节流，它不保证接收方收到的数据块和发送方发送的数据块具有对应大小关系，例如，发送方应用程序交给发送方的TCP10个数据块，但接收方的TCP可能只用了4个数据块就把收到的字节流交付给上层的应用程序，但字节流完全一样。
    \end{itemize}

    \textbf{TCP的可靠性原理：}

    \begin{itemize}
        \item 传输信道无差错,保证传输数据正确;
        \item 不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据;
        \item 首先，采用三次握手来建立TCP连接，四次挥手来释放TCP连接，从而保证建立的传输信道是可靠的。
        \item 其次，TCP采用了连续ARQ协议（回退N，Go-back-N；超时自动重传）来保证数据传输的正确性，使用滑动窗口协议来保证接方能够及时处理所接收到的数据，进行流量控制。
        \item 最后，TCP使用慢开始、拥塞避免、快重传和快恢复来进行拥塞控制，避免网络拥塞。
    \end{itemize}

    \textbf{UDP（User Datagram Protocol）协议的特点：}

    \begin{itemize}
        \item UDP是无连接的传输层协议；
        \item UDP使用尽最大努力交付，不保证可靠交付；
        \item UDP是面向报文的，对应用层交下来的报文，不合并，不拆分，保留原报文的边界；
        \item UDP没有拥塞控制，因此即使网络出现拥塞也不会降低发送速率；
        \item UDP支持一对一　一对多　多对多的交互通信；
        \item UDP的首部开销小，只有8字节．
    \end{itemize}

    \textbf{TCP和UDP的区别：}

    \begin{itemize}
        \item TCP是可靠传输,UDP是不可靠传输;
        \item TCP面向连接,UDP无连接;
        \item TCP传输数据有序,UDP不保证数据的有序性;
        \item TCP不保存数据边界,UDP保留数据边界;
        \item TCP传输速度相对UDP较慢;
        \item TCP有流量控制和拥塞控制,UDP没有;
        \item TCP是重量级协议,UDP是轻量级协议;
        \item TCP首部较长20字节,UDP首部较短8字节;
    \end{itemize}

    基于TCP的常见应用层协议，包括但不限于，HTTP、HTTPS、FTP、Telenet、SMTP；

    基于UDP的常见应用层协议，包括但不限于，DNS、DHCP、TFTP（Trivial File Transfer Protocol）、SNMP（Simple Network Management Protocol）、RIP（Routing Information Protocol）；

    TCP的应用场景是，效率要求相对低，但对准确性要求相对高的场景。因为传输中需要对数据确认、重发、排序等操作，相比之下效率没有UDP高。举几个例子：文件传输（准确高要求高、但是速度可以相对慢）、接受邮件、远程登录。

    UDP的应用场景是，效率要求相对高，对准确性要求相对低的场景。举几个例子：QQ聊天、在线视频、网络语音电话（即时通讯，速度要求高，但是出现偶尔断续不是太大问题，并且此处完全不可以使用重发机制）、广播通信（广播、多播）。

    \subsubsection{HTTP，1.0，1.1，2之间的区别}

    \href{https://www.iamshuaidi.com/681.html}{HTTP，1.0，1.1，2之间的区别}

    HTTP1.0中，TCP连接不能被复用；

    HTTP1.1中，TCP连接可以被复用（持久连接），也加入了管道机制；

    HTTP2中，加入了多路复用，加入了二进制分帧，header压缩，服务端推送。

    \subsubsection{HTTP GET与HTTP POST的区别以及各自的应用场景}

    \href{https://www.iamshuaidi.com/683.html}{HTTP GET与HTTP POST的区别以及各自的应用场景}

    GET用于请求资源，POST用于传输消息实体。

    GET的参数，只能添加在URL的查询字符串中，POST的参数，则添加在实体主体中。

    \subsubsection{HTTP的常用状态码，及应用场景}

    \href{https://www.iamshuaidi.com/693.html}{HTTP的常用状态码，及应用场景}

    1xx表示目前还是中间状态，需要后续请求；

    2xx表示请求成功；

    3xx表示重定向状态，需要重新请求；

    4xx表示请求的报文错误；

    5xx表示服务器端错误；

    101，Switching Protocol，服务器应客户端请求，正在切换协议，例如从HTTP到WebSocket；

    200，OK，请求成功，有响应体；

    301，Moved Permanently，永久重定向，会缓存重定向的结果（这次访问这个网站被永久重定向了，浏览器就会记住这个重定向的结果）；

    302，Found，临时重定向，不会缓存重定向的结果；

    304，Not Modified，协商缓存命中，表示请求的资源自从上次被访问以来没有被修改，可以继续使用本地缓存；

    403，Forbidden，服务器禁止访问；

    404，Not Found，资源没有找到；

    400，Bad Request，请求错误；

    500，Internal Server Error，服务器端错误；

    503，Service Unavailable，服务器繁忙；

    \href{https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status}{【MDN】HTTP响应状态码}

    \subsubsection{HTTP，Connection，keep-alive}

    \href{https://www.iamshuaidi.com/700.html}{HTTP，Connection，keep-alive}

    HTTP1.0中，可以通过Header中的Connection: keep-alive来实现长连接。

    HTTP1.1中，默认为长连接；

    也可以设置，Connection: timeout，来设置闲置多少时间之后，关闭这个TCP连接。

    TCP的keep-alive 包含三个参数，支持在系统内核的 net.ipv4 里面设置：当 TCP 连接之后，闲置了 tcp-keepalive-time 这么长的时间后，则会发送侦测包，如果没有收到对方的 ACK，那么会每隔 tcp-keepalive-intvl 这么长时间再发一次侦测包，直到发送了 tcp-keepalive-probes 次侦测包，就会丢弃该连接。

    \subsubsection{IP地址的分类}

    \href{https://www.iamshuaidi.com/704.html}{IP地址的分类}

    A类地址(1\~126)：网络号占前8位，以0开头，主机号占后24位。

    B类地址(128\~191)：网络号占前16位，以10开头，主机号占后16位。

    C类地址(192\~223)：网络号占前24位，以110开头，主机号占后8位。

    D类地址(224\~239)：以1110开头，保留位多播地址。

    E类地址(240\~255)：以1111开头，保留位今后使用。

    \subsubsection{五层模型，每一层上面都有什么协议}

    \href{https://www.iamshuaidi.com/1283.html}{五层模型，每一层上面都有什么协议}

    \begin{itemize}
        \item \textbf{物理层，}中继器、集线器、网线、HUB。
        \item \textbf{数据链路层，}ARQ，Automated Repeat reQuest，自动重传请求协议；CSMA/CD，Carrier Sense Multiple Access with Collision Detection；停止等待协议；PPP，Point-to-Point Protocol，点对点协议。
        \item \textbf{网络层，}IP协议，ARP，Address Resolution Protocol，地址解析协议；RARP，Reverse Address Resolution Protocol，逆地址解析协议；ICMP，Internet Control Message Protocol，互联网控制报文协议；IGMP，Internet Group Management Protocol，互联网组管理协议；RIP，Router Information Protocol，路由信息协议；OSPF，Open Shortest Path First，开放最短路径优先；BGP，Border Gateway Protocol，边界网关协议。
        \item \textbf{传输层，}TCP、UDP。
        \item \textbf{应用层，}HTTP，FTP，SMTP，DNS，DHCP，SSH，Secure Shell，安全外壳；Telenet，Teletype Network，远程登陆协议。
    \end{itemize}

    \textbf{ARQ}，主要包含停等ARQ、连续ARQ，其中，连续ARQ是为了解决停等ARQ信道利用率低的问题，连续ARQ主要包括，回退N帧ARQ、选择性重传ARQ。

    停等ARQ中，滑动窗口的大小为1，即发送方每发送一个帧，就必须等接收方回复一个ACK，然后再继续发送。

    连续ARQ则会连续发送一组帧，接收方一般采用累积确认模式。

    对于回退N帧ARQ，接收端从第一个没有收到的帧开始，丢弃后面所有的帧，然后发送没有收到的帧的NAK，然后发送端从NAK中指明的帧开始重新发送。

    对于选择性重传ARQ，发送端对每一个发送的帧都设有一个计时器，如果超时没有收到ACK，就重新发送那个帧。

    \textbf{RIP协议}，是早期的动态路由协议，通过UDP报文进行路由信息的交换，使用520端口，基于跳数（最大15）来衡量到达目的地的距离。使用RIP协议的路由器，会自动向邻居发送自己的信息，并收集邻居发来的信息，RIP会维护一个路由表，路由表中存储着自己到其他路由器的距离信息。

    \textbf{OSPF协议}，\href{https://info.support.huawei.com/info-finder/encyclopedia/zh/OSPF.html}{OSPF}，\href{https://zhuanlan.zhihu.com/p/41341540}{OSPF}，

    \textbf{网络层的 ARP 协议}完成了 IP 地址与物理地址的映射。首先，每台主机都会在自己的 ARP 缓冲区中建立一个 ARP 列表，以表示 IP 地址和 MAC 地址的对应关系。当源主机需要将一个数据包要发送到目的主机时，会首先检查自己 ARP 列表中是否存在该 IP 地址对应的 MAC 地址：如果有，就直接将数据包发送到这个 MAC 地址；如果没有，就向本地网段发起一个 ARP 请求的广播包，查询此目的主机对应的 MAC 地址。

    此 ARP 请求数据包里包括源主机的 IP 地址、硬件地址、以及目的主机的 IP 地址。网络中所有的主机收到这个 ARP 请求后，会检查数据包中的目的 IP 是否和自己的 IP 地址一致。如果不相同就忽略此数据包；如果相同，该主机首先将发送端的 MAC 地址和 IP 地址添加到自己的 ARP 列表中，如果 ARP 表中已经存在该 IP 的信息，则将其覆盖，然后给源主机发送一个 ARP 响应数据包，告诉对方自己是它需要查找的 MAC 地址；源主机收到这个 ARP 响应数据包后，将得到的目的主机的 IP 地址和 MAC 地址添加到自己的 ARP 列表中，并利用此信息开始数据的传输。如果源主机一直没有收到 ARP 响应数据包，表示 ARP 查询失败。

    \subsubsection{拆包和粘包}

    \href{https://www.iamshuaidi.com/1310.html}{拆包和粘包}

    UDP有消息保护边界，不会发上拆包和粘包的问题，UDP只会发生丢包和乱序的问题，只有TCP会有拆包和粘包的问题。

    操作系统在进行TCP发送时，会使用缓冲区进行优化；如果应用程序请求发送的数据较少，没有达到缓冲区的大小，TCP则会将多个请求合并进行发送，就发生了粘包的问题；如果应用程序请求发送的数据较多，超过了缓冲区大大小，TCP则会将其拆分进行发送，这就是拆包。

    常见的解决方案有，发送端将每个包都封装成固定的长度，比如100字节大小。如果不足100字节可通过补0或空等进行填充到指定长度；发送端在每个包的末尾使用固定的分隔符，例如\textbackslash r \textbackslash n 。如果发生拆包需等待多个包发送过来之后再找到其中的 \textbackslash r \textbackslash n 进行合并；例如，FTP协议；将消息分为头部和消息体，头部中保存整个消息的长度，只有读取到足够长度的消息之后才算是读到了一个完整的消息；通过自定义协议进行粘包和拆包的处理。

    MTU，Maximum Transmission Unit，最大传输单元，以太网的最大传输单元一般是1500字节。

    MSS，Maximum Segment Size，TCP通信双方通信时，每一个报文段能承载的最大数据长度，   如果是以太网环境，MSS = MTU - 20字节TCP报文头 - 20字节IP报文头 = 1460字节。

    \subsubsection{常见的HTTP方法}

    \href{https://www.iamshuaidi.com/1318.html}{常见的HTTP方法}

    HTTP GET，HTTP POST；
    
    HTTP HEAD 请求资源的头部信息，并且这些头部与 HTTP GET 方法请求时返回的一致。该请求方法的一个使用场景是在下载一个大文件前先获取其大小再决定是否要下载，以此可以节约带宽资源。

    HTTP PUT 使用请求中的负载创建或者替换目标资源，PUT幂等，POST不幂等，PUT没有验证机制。

    HTTP PATCH 用于对资源进行部分修改（PUT是完全替换或者新建）。

    HTTP OPTIONS 用来查询指定的URL支持多少HTTP方法。

    HTTP CONNECT 开启一个客户端与所请求资源之间的双向沟通的通道。它可以用来创建隧道（tunnel）。

    HTTP TRACE 实现沿通向目标资源的路径的消息环回（loop-back）测试，提供了一种实用的 debug 机制。追踪路径。服务器会将通信路径返回给客户端。发送请求时，在 Max-Forwards 首部字段中填入数值，每经过一个服务器就会减 1，当数值为 0 时就停止传输。通常不会使用 TRACE，并且它容易受到 XST 攻击（Cross-Site Tracing，跨站追踪）。

    HTTP DELETE 用于删除指定的资源，功能与PUT相反，同样没有验证机制。

    \subsubsection{在浏览器地址栏中输入URL，到网页加载完成的过程是怎样的}

    \href{https://www.iamshuaidi.com/1320.html}{在浏览器地址栏中输入URL，到网页加载完成的过程是怎样的}

    \begin{itemize}
        \item \textbf{DNS解析}，浏览器需要先查询DNS，找到域名对应的DNS地址，包括，搜索浏览器自己的DNS缓存，搜索操作系统的DNS缓存，读取本地Host文件，向本地DNS服务器进行查询。
        \item \textbf{TCP连接}，通过DNS服务取得的IP地址，浏览器发起TCP连接请求，进行三次握手。
        \item \textbf{发送HTTP请求}，TCP连接建立之后，浏览器发送HTTP请求。
        \item \textbf{服务器处理HTTP请求，返回HTTP报文}，服务器收到请求之后，根据请求的路径和参数，映射到特定的请求处理器上进行处理，并将处理结果和相应的视图返回给浏览器。
        \item \textbf{浏览器解析、渲染页面}，浏览器解析并渲染视图，如果遇到js文件、css文件、图片等静态资源，则重复进行HTTP请求获取这些资源然后进行渲染，最后给用户呈现一个完整的页面。
    \end{itemize}

    \subsubsection{DNS的解析过程}

    \href{https://www.iamshuaidi.com/1322.html}{DNS的解析过程}

    以迭代的方式进行，如果本地DNS服务器存有主机查询的域名，则直接返回结果，如果本地DNS不包含主机请求查询的域名，则本地DNS服务器会以客户的身份，向根域名服务器发出查询请求报文，将查询到的结果返回给主机。

    本地域名服务器向根域名服务器的查询的迭代查询。迭代查询的特点：当根域名服务器收到本地域名服务器发出的迭代查询请求报文时，要么给出所要查询的 IP 地址，要么告诉本地服务器：“你下一步应当向哪一个域名服务器进行查询”。然后让本地服务器进行后续的查询。根域名服务器通常是把自己知道的顶级域名服务器的 IP 地址告诉本地域名服务器，让本地域名服务器再向顶级域名服务器查询。顶级域名服务器在收到本地域名服务器的查询请求后，要么给出所要查询的 IP 地址，要么告诉本地服务器下一步应当向哪一个权限域名服务器进行查询。最后，本地域名服务器得到了所要解析的 IP 地址或报错，然后把这个结果返回给发起查询的主机。

    \href{https://blog.csdn.net/bangshao1989/article/details/121913780}{其他参考，CSDN}

    \href{https://zhuanlan.zhihu.com/p/88260838}{其他参考，知乎}

    \subsubsection{域名缓存}

    \href{https://www.iamshuaidi.com/1324.html}{域名缓存}

    主机自己，和本地DNS服务器，都会有域名缓存，用来存放最近查询过的域名的映射关系，以及从何处获得的域名映射信息的记录。

    域名的映射信息并不会经常改变，因此，域名缓存中的内容，只需要定期进行更新，即，为每一条缓存设置一个定时器，定时器到期后删除对应的缓存信息。

    缓存有效期，从对应的Name Server获取。

    \subsubsection{HTTPS的四次握手过程}

    \href{https://www.iamshuaidi.com/1328.html}{HTTPS的四次握手过程}

    \begin{enumerate}
        \item \textbf{TLS第一次握手}，客户端推送Client Hello消息，包含客户端使用的TLS版本号、支持的加密套件列表、客户端生成的随机数（Client Random，用于生成对称加密密钥）。
        \item \textbf{TLS第二次握手}，服务器确认TLS版本是否支持，并从加密套件中选择一个，生成服务器随机数（Server Random），然后，服务器返回Server Hello消息，包含上述信息。
        \item 然后，服务器推送Server Certificate，即推送服务器的数字证书，然后，服务器发送Server Hello Done消息，表示第二次握手结束。
        \item \textbf{TLS第三次握手}，客户端验证数字证书成功之后，生成一个新的随机数，pre-master，并使用服务器的公钥加密pre-master，然后，客户端发送消息Client Key Exchange，将pre-master传递给服务器。
        \item 然后，客户端和服务器双方，通过共享的，Client Random、Server Random、pre-master，三个随机数，生成对称加密使用的密钥，Master Secret。
        \item 客户端生成密钥之后，向服务器发送Change Cipher Spec，通知服务器开始使用加密的方式发送消息。
        \item 然后，客户端发送一个Encrypted Handshake Message（Finish），将之前发送过的所有数据做一个摘要，并使用Master Secret进行加密，用来给服务器做个验证，验证加密通讯的有效性。
        \item \textbf{TLS第四次握手}，服务器同样向客户端发送Change Cipher Spec和Encrypted Handshake Message（Finish）消息，验证无误之后，加密通信开始，HTTPS建立。
    \end{enumerate}

    \href{https://zhuanlan.zhihu.com/p/344086342}{知乎参考}

    \paragraph{HTTPS的优点}~{}

    \begin{itemize}
        \item HTTPS可以建立双向加密通信，能够确保数据在正确的客户端和正确的服务器之间传递；
        \item HTTPS可以防止数据在传输过程中被改变、窃取，保证数据的完整性。
        \item HTTPS是现行架构下，最安全的解决方式，虽然无法确保绝对安全，但是大大增加了中间人攻击的成本。
    \end{itemize}

    \paragraph{HTTPS的缺点}~{}

    \begin{itemize}
        \item 数字证书要钱的，功能越多的证书越贵（DV、OV、EV），个人网站小网站用不起；
        \item 数字证书通常需要绑定IP，不能再在同一个IP上绑定多个域名（SSL有扩展可以解决这个问题，但是需要浏览器和操作系统的支持）
        \item HTTPS的连接缓存没有HTTP高效。
        \item HTTPS占用的服务器资源更多，握手阶段比较费时，据ACM CoNEXT数据显示，使用https协议会使页面的加载时间延长近50\%，增加10\%到20\%的耗电，此外，https协议还会影响缓存，增加数据开销和功耗，甚至已有安全措施也会受到影响也会因此而受到影响。
        \item HTTPS 协议的加密范围也比较有限，在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。最关键的，SSL 证书的信用链体系并不安全，特别是在某些国家可以控制 CA 根证书的情况下，中间人攻击一样可行。
    \end{itemize}

    \subsubsection{Session和Cookie}

    \href{https://www.iamshuaidi.com/1998.html}{Session和Cookie}

    由于HTTP协议是无状态的协议，所以服务端需要记录用户的状态时，就需要用某种机制来识具体的用户，这个机制就是Session。

    这个Session是保存在服务端的，有一个唯一标识。在服务端保存Session的方法很多，内存、数据库、文件都有。集群的时候也要考虑Session的转移，在大型的网站，一般会有专门的Session服务器集群，用来保存用户会话，这个时候 Session 信息都是放在内存的，使用一些缓存服务比如Memcached之类的来放 Session。

    每次HTTP请求的时候，客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的，第一次创建Session的时候，服务端会在HTTP协议中告诉客户端，需要在 Cookie 里面记录一个Session ID，以后每次请求把这个会话ID发送到服务器，我就知道你是谁了。

    Session是在服务端保存的一个数据结构，用来跟踪用户的状态，这个数据可以保存在集群、数据库、文件中。

    Cookie是客户端保存用户信息的一种机制，用来记录用户的一些信息，也是实现Session的一种方式。

    \subsubsection{应用层封装UDP实现可靠传输}

    \href{https://www.iamshuaidi.com/3615.html}{应用层封装UDP实现可靠传输}

    可以参考TCP的方式，设置一些机制，来确保可靠传输，只不过实现从传输层转移到了应用层。

    \begin{itemize}
        \item 添加seq、ack机制，确保数据成功发送；
        \item 添加发送和接收缓冲区，实现超时重传；
    \end{itemize}

    这样思路的实现有，RUDP（Reliable User Datagram Protocol），RTP（Real Time Protocol）、UDT（UDP-based Data Transfer Protocol）。

    \subsubsection{DNS服务中，TCP和UDP的使用}

    \href{https://www.iamshuaidi.com/4110.html}{DNS服务中，TCP和UDP的使用}

    主域名服务器向辅域名服务器传输数据，进行数据同步的时候，使用TCP，因为数据量大，所以使用允许报文长度更长的TCP，也为了保证数据的正确性，使用可靠连接的TCP。

    当客户端向DNS服务器请求域名解析服务的时候，所传输的数据一般不会超过这种情况下UDP允许的最大报文长度，512字节，这个场景使用UDP能大大提高响应速度，但是要求客户端和域名服务器自己处理超时重传。

    但是，这里就有个问题了。UDP支持的最大数据不是受限于以太网帧的MTU1500字节吗？那么计算下来，也应该是1500-20-8=1472字节啊。怎么就是512了？

    进行了一波搜索，终于找到原因了。以太网帧在局域网中的MTU是1500byte，但是在非局域网环境，如：internet下的时候，MTU是各个路由器进行一个配置的。所以，通常路由器默认的MTU为576字节。所以，为了适应网络环境，DNS协议在返回的数据报大于512的时候，就转化为了TCP协议。

    \href{https://taifua.com/udp-512bytes-limit.html}{UDP报文在不同环境下的长度限制}

    \subsubsection{URL和URI的区别}

    \href{https://www.iamshuaidi.com/4114.html}{URL和URI的区别}

    URL，Uniform Resource Locator；

    URI，Uniform Resource Identifier；

    URL可以通俗的理解为，上网用的网址，URL是URI的一个子集，URI是一个抽象的概念。

    \subsubsection{ICMP的应用}

    \href{https://www.iamshuaidi.com/4122.html}{ICMP的应用}

    Ping命令，用来测试两台主机之间是否可以连通。Ping的原理是，向目标主机发送ICMP Echo请求报文，远方主机收到之后会回复Echo应答报文。

    Traceroute命令（Linux），用来跟踪一个分组从源点到终点的路径，使用无法交付的UDP报文实现。

    \subsubsection{NAT，Network Address Translation，网络地址转换协议}

    \href{https://www.iamshuaidi.com/3997.html}{NAT，Network Address Translation，网络地址转换协议}

    通过网关，实现内网的IP+端口号和网关的IP+端口号的映射，网关帮内网主机访问外网资源，再将请求结果转发回内网主机。

    NAT介于网络层和传输层之间，既不属于网络层也不属于传输层。

    \subsubsection{LAN、WAN、WLAN、VLAN、VPN}

    \href{https://www.iamshuaidi.com/9280.html}{LAN、WAN、WLAN、VLAN、VPN}

    LAN，Local Area Network，局域网，

    WAN，Wide Area Network，广域网，

    WLAN，Wireless Local Area Network，无线局域网，

    VLAN，Virtual Local Area Network，虚拟局域网，将一个物理上的LAN在逻辑上划分为多个广播域，避免局域网中主机较多时，广播泛滥，冲突严重，性能下降；同一个VLAN中的主机可以自由通信，不同VLAN中的主机不能相互通信。

    VPN，Virtual Private Network，虚拟私有网络，

    \clearpage
    \subsection{操作系统}

    \subsubsection{并发和并行}

    \href{https://www.iamshuaidi.com/1349.html}{帅地}

    \underline{\textbf{以下内容来自《Go in Action》：}}

    \textbf{并发，Concurrency}，指的是，同时管理很多事情，这些事情可能做到一半就被暂停去做别的事情了。

    \textbf{并行，Parallelism}，指的是，不同的代码片段，在同一时刻，在不同的物理处理器上执行，并行的关键是，同时做很多的事情。

    在很多情况下，并发的效果比并行好。

    \underline{\textbf{以下内容来自《CSAPP》：}}

    \textbf{并发（Concurrency）}是一个通用的概念，指一个同时具有多个活动的系统；\textbf{并行（Parallelism）}指的是用并发来使得一个系统运行的更快。

    并行可以在一个系统的多个抽象层上运行。

    进程/线程级的并行，指令级的并行，单指令多数据的并行（SIMD）并行。

    \underline{\textbf{以下来自其他资料}}

    并发指的是一种多个任务同时运行的现象，哪怕是单核处理器通过快速的上下文切换来让多个进程看上去在同时运行，也是并发。

    单核处理器通过上下文快速切换来让多个进程看上去在同时运行，属于并发，哪怕某一特定时刻只会有一个进程在真正执行。

    并行则要求物理上真的有多个任务在同时进行。

    \subsubsection{进程和线程的基本概念、进程的知识}

    \href{https://www.iamshuaidi.com/1353.html}{参考-帅地}，\href{https://www.iamshuaidi.com/1355.html}{参考-帅地}，\href{https://zhuanlan.zhihu.com/p/114453309}{参考-知乎}，\href{https://xiaolincoding.com/os/4_process/process_base.html}{参考，小林coding}

    进程是资源分配的最小单位，线程是CPU调度的最小单位。

    进程的创建和撤销，操作系统都要为其分配或者回收资源，操作系统的开销远大于创建或者撤销线程时候的开销。

    不同的进程，虚拟地址空间互相独立，而同一个进程内的线程则会共享虚拟地址空间。一个进程的线程在另一个进程里是不可见的。

    进程之间不会相互影响，而一个线程挂掉则可能导致整个线程挂掉。

    一个进程对应一个应用程序，是竞争计算机系统资源的基本单位。线程是进程的执行单元。

    线程之间，共享所属进程的虚拟地址空间，而进程之间的虚拟地址空间则是独立的。同一个进程的线程，共享诸如内存，IO，CPU等资源。

    进程间的通信方式，有，管道（速度慢，通量有限，只能在父子进程之间）、FIFO（任何进程间都能进行通讯，但是速度慢）、消息队列（容量受到系统的限制，每次读取的时候要考虑上次数据有没有读完的问题）、信号量（不能传递复杂消息，只能做同步）、共享内存区（能很容易的控制容量，速度也比较快，但是要注意安全和同步的问题），等。

    一个进程的活动期间至少具备三种基本状态，即运行状态、就绪状态、阻塞状态。

    \begin{figure}[H]
        \centering
        \includegraphics[scale=0.7]{Figures/进程的三种状态.png}
        \caption{进程的三种状态}
    \end{figure}

    上图各个状态的含义：

    \begin{itemize}
        \item 运行状态（Running）：该时刻进程占用 CPU；
        \item 就绪状态（Ready）：可运行，由于其他进程处于运行状态而暂时停止运行；
        \item 阻塞状态（Blocked）：该进程正在等待某一事件发生（如等待输入/输出操作的完成）而暂时停止运行，这时，即使给它CPU控制权，它也无法运行；
    \end{itemize}

    除此之外，进程还有两个状态，创建状态（new）：进程正在被创建时的状态；结束状态（Exit）：进程正在从系统中消失时的状态；

    如果操作系统中，有大量的进程处于阻塞状态，就会过多的占用物理内存造成浪费，所以，在实际的虚拟内存管理中，通常会将挂起的进程从物理内转移到硬盘中，需要再次进入运行状态的时候，再从硬盘中转移到物理内存中。

    阻塞的进程被转移到硬盘中，这种状态被称为挂起状态，挂起状态也分为两种，阻塞挂起状态和就绪挂起状态。

    在操作系统中，是用进程控制块（process control block，PCB）数据结构来描述进程的。PCB 是进程存在的唯一标识，这意味着一个进程的存在，必然会有一个 PCB，如果进程消失了，那么 PCB 也会随之消失。

    进程控制块，包含的信息具体如下：

    \begin{itemize}
        \item \textbf{进程描述信息}，进程标识符：标识各个进程，每个进程都有一个并且唯一的标识符；用户标识符：进程归属的用户，用户标识符主要为共享和保护服务；
        \item \textbf{进程控制和管理信息}，进程当前状态，如 new、ready、running、waiting 或 blocked 等；进程优先级：进程抢占 CPU 时的优先级；
        \item \textbf{资源分配清单}，有关内存地址空间或虚拟地址空间的信息，所打开文件的列表和所使用的 I/O 设备信息。
        \item \textbf{CPU相关信息}，CPU 中各个寄存器的值，当进程被切换时，CPU 的状态信息都会被保存在相应的 PCB 中，以便进程重新执行时，能从断点处继续执行。
    \end{itemize}

    进程控制块PCB通常通过链表的方式进行组织，把具有相同状态的进程链在一起，组成各种队列。比如，将所有处于就绪状态的进程链在一起，称为就绪队列；把所有因等待某事件而处于等待状态的进程链在一起就组成各种阻塞队列；另外，对于运行队列在单核 CPU 系统中则只有一个运行指针了，因为单核 CPU 在某个时间，只能运行一个程序。

    \textbf{进程的创建过程}，操作系统允许一个进程创建另一个进程，而且允许子进程继承父进程所拥有的资源。1）、申请一个空白的 PCB，并向 PCB 中填写一些控制和管理进程的信息，比如进程的唯一标识等；2）、为该进程分配运行时所必需的资源，比如内存资源；3）、将 PCB 插入到就绪队列，等待被调度运行；

    \textbf{进程的终止过程}，进程可以有 3 种终止方式：正常结束、异常结束以及外界干预（信号 kill 掉）。当子进程被终止时，其在父进程处继承的资源应当还给父进程。而当父进程被终止时，该父进程的子进程就变为孤儿进程，会被 1 号进程收养，并由 1 号进程对它们完成状态收集工作。

    进程的终止过程如下：

    \begin{itemize}
        \item 查找需要终止的进程的 PCB；
        \item 如果处于执行状态，则立即终止该进程的执行，然后将 CPU 资源分配给其他进程；
        \item 如果其还有子进程，则应将该进程的子进程交给 1 号进程接管；
        \item 将该进程所拥有的全部资源都归还给操作系统；
        \item 将其从 PCB 所在队列中删除；
    \end{itemize}

    \textbf{进程的阻塞过程}，当进程需要等待某件事情完成时，可以调用阻塞语句将自己阻塞等待，一旦进入阻塞等待状态，就只能由另一个进程进行唤醒。

    \begin{itemize}
        \item 找到需要被阻塞的进程的PCB；
        \item 如果该线程正处于运行状态，则保护其现场，将其状态转为阻塞状态，并停止其运行；
        \item 将其PCB插入进阻塞队列中；
    \end{itemize}

    \textbf{进程的唤醒过程}，如下

    \begin{itemize}
        \item 在对应事件的阻塞队列中，找到对应进程的PCB；
        \item 将PCB从阻塞队列中移出，并将其状态设置为就绪状态；
        \item 将这个PCN插入到就绪队列中，等待调度程序调度；
    \end{itemize}

    \paragraph{进程的上下文切换}~{}

    CPU从运行一个进程切换到运行另一个进程，称之为上下文切换。CPU在运行一个任务的时候，需要知道任务从哪里加载，又从哪里开始运行。所以，操作系统需要帮助CPU设置好CPU的\textbf{寄存器和程序计数器}。程序计数器存储CPU正在执行或者即将执行的指令的位置，CPU的寄存器和程序计数器是CPU运行任何任务都必须依赖的环境，这被称为\textbf{CPU上下文}。

    CPU的上下文切换，就是把上一个任务的寄存器内容和程序计数器内容保存下来，然后加载下一个任务的寄存器内容和程序计数器内容，最后跳转到新的程序计数器所指向的位置，开始运行新任务。

    操作系统内核负责保存每个任务的CPU上下文信息。

    CPU需要处理的任务，主要包含\textbf{进程、线程、中断}，因此，CPU的上下文切换，也主要分为三种，即，进程上下文切换，线程上下文切换，中断上下文切换。

    进程由内核进行管理和调度，所以进程的切换发生在操作系统的内核态。所以，进程的上下文切换不仅包含了虚拟内存、栈、全局变量等用户空间的资源，还包括了内核堆栈、寄存器等内核空间的资源。通常，会把交换的信息保存在进程的 PCB，当要运行另外一个进程的时候，我们需要从这个进程的 PCB 取出上下文，然后恢复到 CPU 中，这使得这个进程可以继续执行。

    进程上下文切换的常见场景如下：

    \begin{itemize}
        \item 为了保证所有进程可以得到公平调度，CPU 时间被划分为一段段的时间片，这些时间片再被轮流分配给各个进程。这样，当某个进程的时间片耗尽了，进程就从运行状态变为就绪状态，系统从就绪队列选择另外一个进程运行；
        \item 进程在系统资源不足（比如内存不足）时，要等到资源满足后才可以运行，这个时候进程也会被挂起，并由系统调度其他进程运行；
        \item 当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时，自然也会重新调度；
        \item 当有优先级更高的进程运行时，为了保证高优先级进程的运行，当前进程会被挂起，由高优先级进程来运行；
        \item 发生硬件中断时，CPU 上的进程会被中断挂起，转而执行内核中的中断服务程序；
    \end{itemize}

    \subsubsection{线程的知识}

    线程是进程中的一条执行流程，同一个进程的线程，共享\textbf{虚拟地址空间、代码段、数据段、打开的文件，等资源}，但是每个线程的寄存器和栈是独立的。

    一个线程的奔溃，有可能导致进程中所有线程的奔溃（C++语言）。

    \paragraph{线程与进程的比较}~{}

    \begin{itemize}
        \item 进程是资源（包括内存、打开的文件等）分配的单位，线程是 CPU 调度的单位；
        \item 进程拥有一个完整的资源平台，而线程只独享必不可少的资源，如寄存器和栈；
        \item 线程同样具有就绪、阻塞、执行三种基本状态，同样具有状态之间的转换关系；
        \item 线程能减少并发执行的时间和空间开销；
    \end{itemize}

    \paragraph{线程如何减小开销}

    \begin{itemize}
        \item 线程的创建时间比进程快，因为进程在创建的过程中，还需要资源管理信息，比如内存管理信息、文件管理信息，而线程在创建的过程中，不会涉及这些资源管理信息，而是共享它们；
        \item 线程的终止时间比进程快，因为线程释放的资源相比进程少很多；
        \item 同一个进程内的线程切换比进程切换快，因为线程具有相同的地址空间（虚拟内存共享），这意味着同一个进程的线程都具有同一个页表，那么在切换的时候不需要切换页表。而对于进程之间的切换，切换的时候要把页表给切换掉，而页表的切换过程开销是比较大的；
        \item 由于同一进程的各线程间共享内存和文件资源，那么在线程之间数据传递的时候，就不需要经过内核了，这就使得线程之间的数据交互效率更高了；
    \end{itemize}

    \paragraph{线程的上下文切换}~{}

    线程是调度的基本单位，进程是资源拥有的基本单位。

    当进行上下文切换的两个线程不属于同一个进程时，切换过程等同于进程的上下文切换。

    当两个线程是属于同一个进程，因为虚拟内存是共享的，所以在切换时，虚拟内存这些资源就保持不动，只需要切换线程的私有数据、寄存器等不共享的数据。此时上下文切换的开销要比进程之间上下文切换的效率高很多。

    \paragraph{线程实现的方式}~{}

    \begin{itemize}
        \item 用户线程（User Thread）：在用户空间实现的线程，不是由内核管理的线程，是由用户态的线程库来完成线程的管理；
        \item 内核线程（Kernel Thread）：在内核中实现的线程，是由内核管理的线程；
        \item 轻量级进程（LightWeight Process）：在内核中来支持用户线程；
    \end{itemize}

    用户线程和内核线程之间，有，一对一，一对多，多对多，的关系。

    用户线程是基于用户态的线程管理库来实现的，那么线程控制块（Thread Control Block, TCB） 也是在库里面来实现的，对于操作系统而言是看不到这个 TCB 的，它只能看到整个进程的 PCB。

    用户线程的模型是一对多的关系。

    所以，用户线程的整个线程管理和调度，操作系统是不直接参与的，而是由用户级线程库函数来完成线程的管理，包括线程的创建、终止、同步和调度等。

    用户线程的优点如下：

    \begin{itemize}
        \item 每个进程都需要有它私有的线程控制块（TCB）列表，用来跟踪记录它各个线程状态信息（PC、栈指针、寄存器），TCB 由用户级线程库函数来维护，可用于不支持线程技术的操作系统；
        \item 用户线程的切换也是由线程库函数来完成的，无需用户态与内核态的切换，所以速度特别快；
    \end{itemize}

    用户线程的缺点如下：

    \begin{itemize}
        \item 由于操作系统不参与线程的调度，如果一个线程发起了系统调用而阻塞，那进程所包含的用户线程都不能执行了。
        \item 当一个线程开始运行后，除非它主动地交出 CPU 的使用权，否则它所在的进程当中的其他线程无法运行，因为用户态的线程没法打断当前运行中的线程，它没有这个特权，只有操作系统才有，但是用户线程不是由操作系统管理的。
        \item 当一个线程开始运行后，除非它主动地交出 CPU 的使用权，否则它所在的进程当中的其他线程无法运行，因为用户态的线程没法打断当前运行中的线程，它没有这个特权，只有操作系统才有，但是用户线程不是由操作系统管理的。
    \end{itemize}

    内核线程是由操作系统管理的，线程对应的 TCB 自然是放在操作系统里的，这样线程的创建、终止和管理都是由操作系统负责。

    内核线程的模型是一对一的关系。

    内核线程的优点：

    \begin{itemize}
        \item 在一个进程当中，如果某个内核线程发起系统调用而被阻塞，并不会影响其他内核线程的运行；
        \item 分配给线程，多线程的进程获得更多的 CPU 运行时间；
    \end{itemize}

    内核线程的缺点：

    \begin{itemize}
        \item 在支持内核线程的操作系统中，由内核来维护进程和线程的上下文信息，如 PCB 和 TCB；
        \item 线程的创建、终止和切换都是通过系统调用的方式来进行，因此对于系统来说，系统开销比较大；
    \end{itemize}

    轻量级进程（Light-weight process，LWP）是内核支持的用户线程，一个进程可有一个或多个 LWP，每个 LWP 是跟内核线程一对一映射的，也就是 LWP 都是由一个内核线程支持，而且 LWP 是由内核管理并像普通进程一样被调度。

    在大多数系统中，LWP与普通进程的区别也在于它只有一个最小的执行上下文和调度程序所需的统计信息。一般来说，一个进程代表程序的一个实例，而 LWP 代表程序的执行线程，因为一个执行线程不像进程那样需要那么多状态信息，所以 LWP 也不带有这样的信息。

    \subsubsection{操作系统的进程/线程调度算法，scheduler}

    在进程的生命周期中，当进程从一个运行状态到另外一状态变化的时候，其实会触发一次调度，例如，从就绪态到运行态、从运行态到阻塞态、从运行态到结束态。

    因为，这些状态变化的时候，操作系统需要考虑是否要让新的进程给 CPU 运行，或者是否让当前进程从 CPU 上退出来而换另一个进程运行。

    \begin{itemize}
        \item \textbf{非抢占式调度算法}，挑选一个进程，然后让该进程运行直到被阻塞，或者直到该进程退出，才会调用另外一个进程，也就是说不会理时钟中断这个事情。
        \item \textbf{抢占式调度算法}，挑选一个进程，然后让该进程只运行某段时间，如果在该时段结束时，该进程仍然在运行时，则会把它挂起，接着调度程序从就绪队列挑选另外一个进程。这种抢占式调度处理，需要在时间间隔的末端发生时钟中断，以便把 CPU 控制返回给调度程序进行调度，也就是常说的时间片机制。
    \end{itemize}

    \paragraph{先来先服务（First Come First Serve, FCFS）算法}~{}

    先来后到，每次从就绪队列选择最先进入队列的进程，然后一直运行，直到进程退出或被阻塞，才会继续从队列中选择第一个进程接着运行。

    这似乎很公平，但是当一个长作业先运行了，那么后面的短作业等待的时间就会很长，不利于短作业。

    FCFS 对长作业有利，适用于 CPU 繁忙型作业的系统，而不适用于 I/O 繁忙型作业的系统。

    \paragraph{最短作业优先（Shortest Job First, SJF）调度算法}~{}

    优先选择运行时间最短的进程来运行，这有助于提高系统的吞吐量。这显然对长作业不利，很容易造成一种极端现象。

    比如，一个长作业在就绪队列等待运行，而这个就绪队列有非常多的短作业，那么就会使得长作业不断的往后推，周转时间变长，致使长作业长期不会被运行。

    \paragraph{高响应比优先 （Highest Response Ratio Next, HRRN）调度算法}~{}

    权衡了短作业和长作业。每次进行进程调度时，先计算「响应比优先级」，然后把「响应比优先级」最高的进程投入运行，「响应比优先级」的计算公式：

    \begin{equation}
        优先权 = \frac{等待时间 + 要求服务时间}{要求服务时间}
    \end{equation}

    如果两个进程的「等待时间」相同时，「要求的服务时间」越短，「响应比」就越高，这样短作业的进程容易被选中运行；

    如果两个进程「要求的服务时间」相同时，「等待时间」越长，「响应比」就越高，这就兼顾到了长作业进程，因为进程的响应比可以随时间等待的增加而提高，当其等待时间足够长时，其响应比便可以升到很高，从而获得运行的机会；

    \paragraph{时间片轮转（Round Robin, RR）调度算法}~{}

    每个进程被分配一个时间段，称为时间片（Quantum），即允许该进程在该时间段中运行。

    如果时间片用完，进程还在运行，那么将会把此进程从 CPU 释放出来，并把 CPU 分配给另外一个进程；

    如果该进程在时间片结束前阻塞或结束，则 CPU 立即进行切换；

    如果时间片设得太短会导致过多的进程上下文切换，降低了 CPU 效率；

    如果设得太长又可能引起对短作业进程的响应时间变长。

    \paragraph{最高优先级（Highest Priority First，HPF）调度算法}~{}

    从就绪队列中选择最高优先级的进程进行运行，静态优先级：创建进程时候，就已经确定了优先级了，然后整个运行时间优先级都不会变化；动态优先级：根据进程的动态变化调整优先级，比如如果进程运行时间增加，则降低其优先级，如果进程等待时间（就绪队列的等待时间）增加，则升高其优先级，也就是随着时间的推移增加等待进程的优先级。

    该算法也有两种处理优先级高的方法，非抢占式和抢占式：非抢占式：当就绪队列中出现优先级高的进程，运行完当前进程，再选择优先级高的进程。抢占式：当就绪队列中出现优先级高的进程，当前进程挂起，调度优先级高的进程运行。

    \subsubsection{进程间的通信方式}

    每个进程的用户地址空间都是独立的，但是内核空间是所有进程都共享的，所以进程之间要互相通信，必须通过内核空间。

    \paragraph{管道}~{}

    管道是单向传输数据的，管道有匿名管道和命名管道，命名管道也被称为FIFO，使用mkfifo命令创建，管道中的数据采用先进先出的方式，往管道中写数据时如果没有被读取，会让写数据的一方堵塞。

    所谓的管道，就是内核里面的一串缓存。从管道的一段写入的数据，实际上是缓存在内核中的，另一端读取，也就是从内核中读取这段数据。另外，管道传输的数据是无格式的流且大小受限。对于匿名管道，它的通信范围是存在父子关系的进程。对于命名管道，它可以在不相关的进程间也能相互通信。

    \paragraph{消息队列}~{}

    消息队列适合频繁的交换数据，消息队列是保存在内核中的消息链表，在发送数据时，会分成一个一个独立的数据单元，也就是消息体（数据块），消息体是用户自定义的数据类型，消息的发送方和接收方要约定好消息体的数据类型，所以每个消息体都是固定大小的存储块，不像管道是无格式的字节流数据。如果进程从消息队列中读取了消息体，内核就会把这个消息体删除。

    消息队列不适合比较大数据的传输。消息队列通信过程中，存在用户态与内核态之间的数据拷贝开销。

    \paragraph{共享内存}~{}

    共享内存的机制，就是拿出一块虚拟地址空间来，映射到相同的物理内存中。这样这个进程写入的东西，另外一个进程马上就能看到了，都不需要拷贝来拷贝去，传来传去，大大提高了进程间通信的速度。

    \paragraph{信号量}~{}

    为了防止多进程竞争共享资源，而造成的数据错乱，所以需要保护机制，使得共享的资源，在任意时刻只能被一个进程访问。正好，信号量就实现了这一保护机制。信号量其实是一个整型的计数器，主要用于实现进程间的互斥与同步，而不是用于缓存进程间通信的数据。

    \paragraph{信号}~{}

    在 Linux 操作系统中， 为了响应各种各样的事件，提供了几十种信号，分别代表不同的意义。我们可以通过 kill -l 命令，查看所有的信号。

    信号是进程间通信机制中唯一的异步通信机制，因为可以在任何时候发送信号给某一进程，一旦有信号产生，我们就有下面这几种，用户进程对信号的处理方式。

    \begin{enumerate}
        \item \textbf{执行默认操作}，Linux 对每种信号都规定了默认操作，例如，上面列表中的 SIGTERM 信号，就是终止进程的意思。
        \item \textbf{捕捉信号}，我们可以为信号定义一个信号处理函数。当信号发生时，我们就执行相应的信号处理函数。
        \item \textbf{忽略信号}，当我们不希望处理某些信号的时候，就可以忽略该信号，不做任何处理。有两个信号是应用进程无法捕捉和忽略的，即 SIGKILL 和 SEGSTOP，它们用于在任何时候中断或结束某一进程。
    \end{enumerate}

    \paragraph{Socket}~{}

    略。

    \clearpage
    \subsection{数据库（MySQL）}

    \subsubsection{事务，Transaction}

    \href{https://blog.csdn.net/justlpf/article/details/106835122}{参考1，CSDN}；

    事务是应用程序中的一系列操作，用来维护数据库的完整性，事务能够保证成批的SQL要么完全执行成功，要么完全不执行（已执行的部分也会被撤销）。

    事务只会以两种方式结束，要么所有操作全部成功，事务提交（Commit）；如果有操作出现错误，事务就会回滚（Rollback），撤销所有操作到事务开始前的状态。

    使用begin transaction开始事务，使用commit或者rollback对事务进行提交或者回滚。

    \textbf{事务的ACID}，事务，具有，原子性（Atomicity）、一致性（Consistency）、隔离性（Isolation）、持续性（Durability）。

    \begin{itemize}
        \item \textbf{原子性，Atomicity}，事务是数据库的逻辑工作单位，事务中包含的各个操作，要么都做，要么都不做。
        \item \textbf{一致性，Consistency}，当数据库中，只包含成功提交的事务产生的结果的时候，数据库就处于一个一致的状态。事务的执行结果，必须使得数据库，从一个一致性状态，转移到另一个，一致性状态。
        \item \textbf{隔离性，Isolation}，一个事务的执行，不能干扰其他事务的执行。一个事务内部的操作和使用的数据对其他并发的事务是隔离的。并发执行的事务之间不能相互干扰。
        \item \textbf{持续性/永久性，Durability}，一个事务一旦提交，它对数据库中的数据的改变就应当是永久的。接下来的其他操作和故障都不应当对已经提交的事务的结果产生影响。
    \end{itemize}

    \subsubsection{事务的隔离级别}

    SQL标准定义了四种隔离的级别，用来限定事务内外的哪些改变是可见的，哪些是不可见的。

    低级别的隔离一般支持更高的并发程度，拥有更低的系统开销。

    \begin{itemize}
        \item \textbf{Read Uncommitted，读取未提交内容：}所有事务都可以看到其他未提交的事务的执行结果，会产生\textbf{脏读（Dirty Read）}的问题。该隔离级别很少用于实际应用，因为性能不比其它隔离级别明显提高。
        \item \textbf{Read Committed，读取提交内容：}大多数数据库的默认隔离级别，但不是MySQL的默认隔离级别。在该隔离级别下，事务只能看到其他已经提交的事务的执行结果。但是仍然会存在\textbf{不可重复读（Non-repeatable Read）}的问题。
        \item \textbf{Repeatable Read，可重复读：}MySQL默认的隔离级别，能够解决不可重复读的问题，但是还会存在\textbf{幻读（Phantom Read）}的问题，即，其他事务插入了新的数据行，导致当前事务前后两次读取的行数不一致。InnoDB和Falcon存储引擎，通过\textbf{多版本并发控制（MVCC，Multi-Version Concurrency Control）}解决了幻读的问题。
        \item \textbf{Serializable，可串行化：}最高的隔离级别，直接将每个事务串行化，不可能存在冲突。
    \end{itemize}

    \subsubsection{脏读、幻读、不可重复读}

    \href{https://blog.csdn.net/qq_42817320/article/details/119905192}{参考1，CSDN}

    实际应用中，一个数据库上会有很多个事务并发执行，进行增删查改，对于MySQl，主要会发生，脏读、幻读、不可重复读，三种问题。

    \paragraph{脏读，Dirty Read}~{}

    事务A修改了一个数据，但是没有提交；事务B读取了事务A修改的未提交数据；然后事务A回滚，事务B读取到的数据不存在了。针对Update。

    解决的方案是，将事务的隔离级别设置为 Read Committed，或者，读取数据时加上排他锁，或者，修改数据时加上共享锁。

    \paragraph{幻读，Phantom Read}~{}

    同一个事务，在前后两次查询中查询到的数据总量不一致，例如，第一次查询到5条，第二次查询到10条，因为中间有别的事务插入了数据。

    解决的方法是，将数据库的隔离级别变为Serializable，变成单线程的数据库。

    \paragraph{不可重复读，Non-repeatable Read}~{}

    同一个事物，在前后两次查询中，查询道德数据内容不一致，因为有其他事务在两次查询中间修改了数据。针对Insert操作。

    解决方法是，将事务的隔离级别设定为Repeatable Read，或者，读取数据时加上共享锁，修改数据时加上排他锁，事务提交了锁再释放。

    \subsubsection{多版本并发控制，MVCC，Multi-Version Concurrency Control}

    -

    \subsubsection{InnoDB与MyISAM}

    \href{https://zhuanlan.zhihu.com/p/75165526}{参考1，知乎}

    InnoDB与MyISAM都是MySQL的\textbf{存储引擎}。数据库存储引擎是数据库的低层软件，数据库管理系统（DBMS）使用存储引擎进行数据的创建、查询、更新、删除。

    不同的存储引擎会提供不同的存储机制、索引技巧、锁定水平，等功能。

    一台服务器上的多个数据库可以使用不同的存储引擎，同一个数据库中不同的表也可以使用不同的存储引擎。

    在MySQL中，使用“SHOW ENGINES”查看支持的存储引擎。

    InnoDB和MyISAM的基本原理都是B+树。

    B树是多路平衡查找树，B+树是B树的升级，效率接近于二分查找。

    \begin{itemize}
        \item InnoDB支持事务，MyISAM不支持事务。InnoDB默认将每一条SQL语句都封装成事务。InnoDB中的B+树中存储的都是实际的数据，这种存储方式被称为聚集索引。
        \item InnoDB支持外键，MyISAM不支持外键。MyISAM中的B+树中存储的是实际数据的地址。
    \end{itemize}

    对于增删改需求比较高的表，建议使用InnoDB；对于查询需求比较高的表，建议使用MyISAM。

    \subsubsection{说一下你对MySQL的了解}

    \href{https://www.iamshuaidi.com/1405.html}{参考，帅地}

    \href{https://blog.csdn.net/qq_39408435/article/details/118667021}{参考，CSDN}

    \begin{figure}[H]
        \centering
        \includegraphics[scale=0.25]{Figures/MySQL-架构图-1.png}
        \includegraphics[scale=0.3]{Figures/MySQL-架构图-2.png}
    \end{figure}

    总的来说，MySQL包括了Server层和存储引擎层，两个部分。

    Server层，主要包含了，连接器、查询缓存、分析器、优化器、执行器，提供了MuySQL的大多数的核心功能和内置函数，所有跨存储引擎的功能都在Server层实现。

    存储引擎，则负责数据的存储和提取。

    不同的存储引擎共用一个Server层。

    \paragraph{网络连接器，Client Connector}~{}

    提供与MySQL Server建立连接的支持，支持绝大多数的编程语言。

    \paragraph{连接池，Connection Pool}~{}

    负责存储和管理，客户端与MySQL Server的连接，一个线程负责管理一个连接。
    
    \paragraph{SQL接口，SQL Inferface}~{}

    直接接受客户端发送来的SQL语句，并向用户交付结果。能够接受，存储过程、视图、触发器、DML（Data Manipulation Language）、DDL（Data Definition Language），等。

    \paragraph{解析器，Parser}~{}

    解析器负责，将SQL接口接收到的SQL语句，解析为一个“解析树”，并检查解析树的合法性。

    \paragraph{查询优化器，Optimizer}~{}

    如果解析器确定SQL语句合法，解析树会被交给优化器，优化器将解析树转化为执行计划，然后交予存储引擎进行处理。

    \paragraph{缓存，Cache and Buffer}~{}

    包含了，表缓存、记录缓存、权限缓存、引擎缓存，等，如果缓存中有可以命中的结果，则可以直接从缓存中获取需要的结果。

    \paragraph{存储引擎，Pluggable Storage Engine}~{}

    负责数据实际的，读取和写入，直接与低层的文件系统进行交互。在MySQL中，存储引擎是插件式的，通过接口与执行器进行交互。

    \subsubsection{SQL语句在MySQL中的执行过程}

    \href{https://www.iamshuaidi.com/1407.html}{参考，帅地}

    \href{https://blog.csdn.net/pcwl1206/article/details/86137408}{参考，CSDN}

    \href{https://time.geekbang.org/column/article/68319}{参考，极客时间}

    \begin{enumerate}
        \item 应用程序，将需要执行的SQL语句，发送给MySQL Server，进行执行。
        \item 首先查询，缓存中，是否有需要的结果，如果有，则直接返回缓存中的结果，如果没有，则进行进一步的操作。
        \item 解析SQL，预处理，生成SQL的执行计划，优化SQL的执行计划。
        \item MySQL根据执行计划完成查询。
        \item 返回结果给客户端。
    \end{enumerate}

    \begin{figure}[H]
        \centering
        \includegraphics[scale=0.2]{Figures/MySQL-架构图-3.png}
    \end{figure}

    连接器需要负责跟客户端，建立连接，获取权限，维持并管理连接。如果管理员对某一用户的权限做出了更改，已经创建的连接不受影响，重新创建的连接才会受影响。MySQl在执行查询的过程中，占用的内存资源是在连接对象里面管理的，容易累计造成内存占用过多。可以定期断开长连接，或者使用MySQL5.7及以后的mysql\_reset\_connection的功能（不做重新连接，但是初始化连接资源）。

    查询缓存以键值对的形式存在于内存中，键是SQL语句，值是查询结果。缓存的失效会很频繁，对于一个表，只要这个表上有一个更新，这个表的所有缓存都会失效。对于更新频繁的数据库而言，缓存的命中率非常低。极少更新的表才适合使用缓存。MySQL8.0已经移除了缓存功能。

    分析器会进行词法分析和语法分析。

    在表里有多个索引的时候，优化器会决定使用哪个索引；在连接的时候，优化器会决定各个表的连接顺序。经过优化器的优化，SQL语句的执行方案就确定了下来。

    通过分析器，MySQL知道了客户要做什么。

    通过优化器，MySQL知道了该怎么做。

    执行器负责最终执行。

    \subsubsection{数据库的三大范式}

    \href{https://www.iamshuaidi.com/1409.html}{参考，帅地}

    \href{https://zhuanlan.zhihu.com/p/590135927}{参考，知乎}

    \paragraph{第一范式}~{}

    强调列的原子性，即，数据库的每一列都是不可分割的原子数据。

    \paragraph{第二范式}~{}

    要求属性完全依赖于主键，即依赖主键的全部，而不是主键的一部分。

    在满足第一范式的情况下，遵循唯一性，消除部分依赖。即，表中任意一个主键或任意一组联合主键，可以确定除该主键外的所有的非主键值。再通俗点讲就是，一个表只能描述一件事情。

    \paragraph{第三范式}~{}

    任何的非主键属性都不依赖于其他的非主键属性。

    在满足第二范式的情况下，消除传递依赖。即，在任一主键都可以确定所有非主键字段值的情况下，不能存在某非主键字段A可以获取某非主键字段B。

    非主键列必须直接依赖于主键，不能存在传递依赖。

    \subsubsection{char 和 varchar 的区别}

    \href{https://www.iamshuaidi.com/1411.html}{参考，帅地}

    \href{https://zhuanlan.zhihu.com/p/91994971}{参考，知乎}

    char(n)是长度固定的字符串类型，长度默认为1，最高为255，，效率高，但是会占用额外的空间，适合存储固定长度的数据。

    varchar(n)是可变长度的字符串类型，可在表定义时，定义最长长度，最长长度最大可以设置为65535，需要额外的字节记录长度，空间利用率更高。

    \href{https://www.iamshuaidi.com/1413.html}{参考，帅地}

    对于varchar(10)和varchar(20)来说，存储一个“hello”所占用的磁盘存储空间是一样的，但是后者在加载到内存中时使用的内存更多（varchar加载到内存中使用固定最长长度），排序时也会消耗更多的资源，因为order by会以固定长度的方式来计算

    \subsubsection{对MySQL中索引的理解}

    \href{https://www.iamshuaidi.com/1415.html}{参考，帅地}

    \href{https://developer.aliyun.com/article/831250}{参考，阿里云开发者社区}

    索引的目的是，提高数据查询的效率，但是索引的创建和维护也需要消耗时间占用空间，在对表进行增删查改时，也需要动态的维护索引。

    索引一般在最频繁使用的，可以缩小查询范围的，或者需要排序的字段上，建立。

    对于查询较少或者重复程度较高的字段，不适合建立索引；对于一些特殊的数据类型，例如文本，也不适合建立索引。

    索引是帮助MySQL高效获取数据的数据结构，能够加快数据库的查询速度。

    索引的类别，包括主键索引、唯一索引、复合索引、全文索引、空间索引、前缀索引。

    \begin{itemize}
        \item 优点，大大提高数据查询的速度；
        \item 优点，提高数据查询的效率，降低查询过程中的IO成本；
        \item 优点，可以通过索引对数据进行排序，降低数据库的排序成本和CPU的消耗；
        \item 优点，被索引的列会自动进行排序；
        \item 优点，按照索引的顺序来进行排序，order by的效率会大大提高；
        \item 缺点，索引会占据额外的存储空间；
        \item 缺点，索引会提高查询的效率，但是会降低增删改的效率，因为增删改的时候，不仅要更新数据库本身，还需要更新索引；
    \end{itemize}

    \subsubsection{B树，B+树}

    \href{https://www.iamshuaidi.com/1420.html}{参考，帅地}

    B表示balance的意思，B树是一种多路自平衡搜索树，B+树是一种多路自平衡查找树。B树专门为外部存储器设计，每个节点可以有上千个子节点，一般被用在文件系统、数据库中。

    像红黑树、AVL树这样的平衡二叉搜索树，需要通过旋转来维持平衡，而旋转操作需要涉及到整棵树，不能支持树部分在内存中部分在硬盘中的情况。所以对于文件系统和数据库的应用场景，需要设计专门的数据结构。

    二叉搜索树，每次索引可以减小一半的搜索范围，在涉及硬盘IO的时候，硬盘的读取速度是系统的瓶颈，所以需要减少硬盘IO的次数，所以就有了多叉树，每次索引可以比二叉树减小更多的搜索范围，这就是B-树。

    B+树的改进在于，真正的数据只在叶子节点上出现，并且叶子节点拥有链指针，能都大大增加连续访问性。

    B+树由于只有叶子节点才会存储数据，所以B+树每一个节点能够放下更多的key，对硬盘IO的消耗更小，树的高度也更低。同时，B+树的叶子节点形成一个链表，更加适合范围查找和排序。

    \begin{itemize}
        \item B+树层数更少，查找更快。
        \item 由于数据都存储在叶子节点，B+树的查找时间非常稳定。
        \item B+树的叶子节点的链指针，是的排序和范围查找非常方便。
    \end{itemize}

    \subsubsection{聚簇索引、哈希索引、覆盖索引}

    \href{https://www.iamshuaidi.com/1426.html}{聚簇索引，帅地}，\href{https://www.iamshuaidi.com/1432.html}{哈希索引，帅地}，\href{https://www.iamshuaidi.com/1435.html}{覆盖索引}。

    \clearpage
    \subsection{C++语言基础}

    \subsubsection{C++指针和引用的区别}

    指针是一个实际上的变量，存储一个虚拟内存地址，指向虚拟内存中的一个实际的对象；

    而引用只是原来的变量的一个别名；

    指针可以套娃（指针的指针），引用不能套娃（右值引用是另一个东西了）；

    指针可以在定义的时候不进行初始化，指针可以为null，指针的值可以被修改；引用在定义的时候必须被初始化，引用不能为null，引用的对象不能再改变；

    \subsubsection{C++模板}

    to be continued

    \subsubsection{C++面向对象，面向对象的三大特性}

    面向对象的三大特性是，封装、继承、多态。

    封装的目的是，保护数据，隐藏细节，仅暴露访问交互接口，保证数据安全。class默认private，struct默认public。

    继承的目的是，扩展功能，实现代码的重用；继承有三种方式，public、protected、private，默认为private继承。

    多态可以实现接口的重用，即一个接口多种方法。静态多态在编译时完成，动态多态在运行时完成。静态多态通过函数的重载（overload）实现，动态多态通过虚函数完成函数的重写（override）实现。

    多态的功能通过虚函数来实现，虚函数通过虚函数表（V-Table）来实现，如果一个类中包含有虚函数，那么这个类就会包含一张虚函数表，表中的每一项是一个虚函数的地址。

    虚函数表是C++为了实现多态而使用的一种动态绑定技术的核心。每个包含了虚函数的类，都会包含有一张虚函数表。

    \subsubsection{构造函数和析构函数可不可以是虚函数，为什么}

    构造函数不可以是虚函数，析构函数可以是虚函数。

    当类中声明虚函数时，编译器会在类中生成一个虚函数表，虚函数表是一个存储成员函数指针的数据结构。

    虚函数表是由编译器自动生成与维护的，virtual成员函数会被编译器放入虚函数表中，当存在虚函数时，每个对象都有一个指向虚函数的指针（vptr指针）。在实现多态的过程中，父类和派生类都有vptr指针。

    vptr的初始化：当对象在创建时，由编译器对vptr指针进行初始化。在定义子类对象时，vptr先指向父类的虚函数表，在父类构造完成之后，子类的vptr才指向自己的虚函数表。

    如果构造函数时虚函数，那么调用构造函数就需要去找vptr，而此时vptr还没有初始化。

    因此，构造函数不可以是虚函数。

    与构造函数不同，vptr已经完成初始化，析构函数可以声明为虚函数，且类有继承时，析构函数常常必须为虚函数。

    \href{https://zhuanlan.zhihu.com/p/255274039}{参考链接}

    \subsubsection{delete[]是怎么知道要释放几个对象的}

    简单的来说，new[]的时候，会记录下申请的数组的长度，最常见的情况是，长度被存储在返回的指针的前面，所以，在delete[]的时候，就能知道要释放多少资源。

    \subsubsection{类和对象的区别}

    在C++中，类是一种用户自定义的数据类型。类定义了一个对象的属性和行为，是实现面向对象编程的基本单元。

    在C++中，对象是类的实例。通过创建对象，可以访问类的成员变量和成员函数。

    \subsubsection{声明（declaration）和定义（definition）的区别}

    声明是，是指出存储类型，并给存储单元指定名称。

    定义是，是分配内存空间，还可为变量指定初始值。

    extern关键字用于声明外部变量，但不进行定义。

    局部变量在声明的同时进行定义，并且可以指定初始值。

    一个变量可以有多个声明，但只能有一个定义。

    函数原型即是函数的声明，带有函数体的才是函数的定义。

    \subsubsection{C与C++中，struct的区别}

    在C语言中，struct是用户自定义数据类型，没有访问权限的概念。

    在C++中，struct是抽象数据类型，支持成员函数的定义，除了默认访问权限外与clss基本相同。

    C++中保留struct更多的是对C语言的一种兼容。

    \subsubsection{覆盖和隐藏}

    派生类将继承的基类的同名的成员变量和成员方法隐藏起来，通过派生类只能访问到自己的成员变量和成员方法。若想要访问基类的成员变量和成员方法需加上基类的作用域。隐藏以后的直接效果就是：无论在派生类的内部或者外部（通过派生类成员）访问该成员；全都是访问派生类的同名成员； 如果在派生类内部或者外部（通过派生类成员）访问同名的成员函数，则需要根据函数调用的规则来调用派生类的同名成员函数。

    覆盖则是通过虚函数达到的重写的效果。

    \subsubsection{strcpy、memcpy、memset}

    memset将一块内存设置为指定的值，一般用于POD（Plain Old Data）对象的初始化。

    memcpy用于内存的复制，但是两块内存不能有重叠，否则会引发未定义的后果。如果不能保证内存不重叠，可以采用memmove函数。

    strcpy可能遇到的问题是，源长度大于目标的长度，解决方案是使用strncpy。

\begin{lstlisting}[language=C++, lineskip=3pt]
char *strcpy(char *dest, const char *src)
char *strncpy(char *dest, const char *src, size_t n)
void *memset(void *str, int c, size_t n)
void *memcpy(void *str1, const void *str2, size_t n)
void *memmove(void *str1, const void *str2, size_t n)
\end{lstlisting}

    \subsubsection{怎么判断线程安全}

    to be continued

    \subsubsection{C++内存分配方式}

    C++中的内存分配，主要有三种方式，静态存储区分配、栈上创建、堆上分配。

    静态存储区的内存，在程序编译时已经分配好，静态存储区在程序的整个生命周期中都存在，存放全局变量、static变量。

    栈主要存储局部变量，函数调用需要使用的空间也在栈上分配，局部变量生命周期结束或者函数调用结束后，对应的栈上的内存会被自动释放。

    从堆上分配内存，也叫做动态内存分配，即在C语言中使用malloc函数和new运算符分配的内存，需要程序员手动使用free函数或者delete运算符进行释放。

    C++程序会在编译时，将内存分为5大存储区：

    \begin{itemize}
        \item 栈，stack。栈区的内存，由编译器自动进行分配和释放。主要存储，局部变量，函数参数。
        \item 堆，heap。堆区的内存，由程序员控制分配和释放。
        \item 静态存储区，存放全局变量和静态变量，分为全局初始化区和全局未初始化区，程序生命周期结束时，由操作系统进行释放。
        \item 字符常量区，存放常量字符串，程序运行结束时操作系统进行释放。
        \item 程序代码区，存放各个函数体的二进制代码。
    \end{itemize}

    \subsubsection{什么是野指针和悬空指针，如何避免}

    野指针指的是没有被初始化的指针，或者指向生命周期已经结束的对象的指针，此时野指针可能指向任意的内存段，容易损坏数据，引发未知错误。

    悬空指针指的是指向已经被释放的内存的指针。

    初始化指针时，赋予其合法的初始值或者置为null，释放内存后，将原来的指针设置为空，尽量使用引用而不是指针。

    \subsubsection{内存泄漏，memory leak}

    是指程序在申请内存后，无法释放已申请的内存空间，一次内存泄露危害可以忽略，但内存泄露堆积后果很严重，无论多少内存,迟早会被占光。最终的结果就是导致内存溢出（out of memory，OOM）。

    指针重新赋值，导致没有被释放的内存的指针丢失，会造成内存泄漏。

    对于结构化的数据，在释放时，如果没有逐个释放也会导致内存泄漏。

    如果某些函数返回指针作为返回值，不正确处理也会导致内存泄漏。

    \subsubsection{C++智能指针}

    C++11中引入了智能指针，主要是，unique ptr，shared ptr。

    \paragraph{unique ptr}~{}

    主要用于可以独占对象的使用场景，unique ptr可以做到，在离开变量的作用域后，自动释放内存。

    unique ptr是move-only的。

    \paragraph{shared ptr}~{}

    shared ptr采用了引用计数的原理，引用计数为0，自动释放资源。

    \subsubsection{C++11多线程}

    to be continued

    \subsubsection{C++怎么获取文件大小}

    Linux平台，可以通过stat系统函数调用实现文件信息的读取，包括文件大小。

    可以读取整个文件，计算大小。

    可以通过移动文件指针的方式，得到文件的大小。

    \subsubsection{设计模式}

    to be continued

    \clearpage
    \section{面经}

    \href{https://kdocs.cn/l/cv2w9VO3ibdE}{宝贝总结的面经}

    \clearpage
    \bibliography{References}
    \bibliographystyle{unsrt}
    
\end{document}
